Vuejs--认识组件

141 阅读5分钟

ToDoList

使用前两天所学的知识,可以做一个很简单的小demo:ToDoList。代码如下:

<div id="root">
			<input v-model="inputValue"/>
			<button  @click="addList">提交</button>
			<ul>
				<li v-for="(item,index) of list"  :key="index">{{item}}</li>
			</ul>
		</div>
		<script>
			new Vue({
				el:"#root",
				data:{
					inputValue:"",
					list:[]
				},
				methods:
				{
					addList:function()
					{
						if(this.inputValue)
						{
							this.list.push(this.inputValue);
							this.inputValue="";
						}
					}
				}
			})
		</script>

简单描述一下实现的过程:首先通过点击提交按钮,触发addList事件,这个事件会把inputValue拉入list中,而inputValue肯定要求就是输入框的value这时候我们就利用双向绑定,把输入框的value值和inputValue进行绑定。最后形成了list这个数组。再通过v-for列表渲染这个list就能得出这个demo了。

ToDoList的组件拆分

组件

组件是什么?

简单来讲组件就是页面的一个部分,当你的页面十分庞大的时候,你可以将它拆分为几个小部分,也就是几个小组件。这样的话,这样的话,维护整个页面的难度就被大大降低。这就是组件开发的思想。

注册组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <script src="./js/vue.js"></script>
</head>
<body>
    <div id="app">
        <cpn></cpn> 
        <cpn></cpn> 
        <cpn></cpn> 
    </div>
    <script>
        const cpn = Vue.extend({//步骤一创建组件构造器对象
            template:
            `<div>
                        <h1>我是猪</h1>
             </div> `
        });
        Vue.component("cpn",cpn);//注册全局组件
     const app = new Vue({
         el:"#app",
         
     })
    </script>
</body>
</html>

第一步:创建组件构造器对象

使用Vue的extend方法创建一个组件构造器对象,它的参数是一个对象,就是组件的全部信息。

  const cpn = Vue.extend({//步骤一创建组件构造器对象
            template://这里我只给组件添加了template 选项。
            `<div>//这里使用的是es6的字符串模板的语法。这样可以换行。
                        <h1>我是猪</h1>
             </div> `
        });

第二步,注册组件

注册组件,其实有两种注册方式

  • 注册全局组件。
    只需要Vue.component("组件名(也就是使用时组件的标签名)",对应的组件组件构造器对象);
    example:
 Vue.component("cpn",cpn);//注册全局组件

那么在它下面注册的vue实例都可以直接用它了,对他们都是可见的,全局的。

  • 注册局部组件
    注册局部组件更简单。创建vue实例或者vue组件的时候,有个options叫components。这个属性就是用来注册局部组件的,在这里面的注册的组件都可以在vue实例或者vue组件中使用。
    example:
    const cpn2 = Vue.extend({//创建组件构造器对象
            template:
            `<div>
                        <h1>你才是</h1>
             </div> `
        });
     const app = new Vue({
         el:"#app",
         components:
         {
             cpn2:cpn2//注册局部组件
         }
     })

components是一个对象。它的属性名,就是组件的标签名。它的属性值就是对应组件的组件构造器对象。 当你注册之后你就可以使用该组件了

第三步,使用组件

  • 全局组件
    全局组件注册好之后,在它下面注册的vue实例是可以无条件用它的。
  • 局部组件 局部组件在组件或实例中注册好之后,是可以在该实例或者组件中,任意使用的,但是它的使用范围仅限这个区间。因为他是局部的

注册组件的语法糖写法

在vue2.x中,其实刚刚那种三步式的写法已经很少了,都是使用语法糖的形式注册组件。其实也很简单,就是将第一步第二步融为一步来操作。跳过创建组件构造器的写法。但是其实vue内部还是在调用Vue.extend()方法。

  • 注册全局组件的语法糖写法
	Vue.component("cpn",{
    template:``,
    ...
    })
  • 注册局部组件的语法糖写法
	new Vue({
    el:"#app",
    components:{
    	cpn:{
        template:``,
        ...
        }
    }
    })

组件模板的分离写法

通常情况下,组件的模板可能很长,如果注册的时候不剥离出来可能代码就会显得很冗余没有结构,所以我们会把组件的模板剥离出来。有两种方式剥离组件的模板。

  • 使用script标签进行剥离。
    注意此时的类型应该是type="text/x-template"
<script type="text/x-template" id="cpn">//设置id属性
        <div>
            <h1>我是猪</h1>
        </div>
    </script>
    <script>
        
        const cpn = Vue.extend({
            template:"#cpn"//template引用id属性
        });
     
        Vue.component("cpn",cpn);
     const app = new Vue({
         el:"#app",
    
     })

如何将我们剥离出来的这个script标签和我们的组件联系起来这里是用id属性,通过id属性将两者联系起来

  • 使用template标签。
    其实同上面的差不太多。同样是通过id属性,关联起来。
 <template id="cpn">
        <div>
            <h1>我是猪</h1>
        </div>
    </template>
    
    <script>
        
        const cpn = Vue.extend({
            template:"#cpn"
        });
     
        Vue.component("cpn",cpn);
     const app = new Vue({
         el:"#app",
    
     })
    </script>

注意事项

1.全局组件要写在vue实例创建前才能在该实例对应的挂载元素内使用它。它只能渲染实例写在它后面的元素。如果一个元素内使用它但是它对应的vue实例创建在这个组件之前,不仅渲染不出来,而且会报错:

<div id="root" >
		<todo-item></todo-item>
	</div>
	<div id="root1">
		<todo-item></todo-item>
	</div>
	<script>
		new Vue({
			el:"#root1",
		})
		Vue.component("todo-item",{
			template:"<li>item</li>"
		})
		new Vue(
		{
			el:"#root",
		}
		)
	</script>

比如这里的#root1
只渲染出#root的组件

并且出现报错: 2. 模板必须有一个根元素且仅有一个根元素。(这一点在前面已经提及)

组件的一些问题

组件的其他属性和vue实例一样,但是data属性是不一样的。

vue实例中的data属性是一个对象。而组件中的data属性是一个函数。要达到实例相同的效果,只要返回一个对象就可以了。

 Vue.component("my-component",{
     template:"<button @click='add3'>" +
     "{{message}}</button>",
     data:function(){
         return {
             message:"hello world"
         }
     }
 });

为什么和vue实例不一样呢?不觉得多此一举嘛。
是为了让每一个组件都有独自的data数据,而不是像vue实例一样共享一个data数据。
举个栗子: (这是我自己写的一个小栗子)这个例子就是模拟的data是一个对象的情况,因为component的data直接写是一个对象是会报错的,只能通过函数返回同一个对象

<body>
	<div id="root" >
		<todo-item></todo-item>
		<todo-item></todo-item>
		<todo-item></todo-item>
	</div>
	<script>
		var data =
		{
			counter:0
		}
		Vue.component("todo-item",{
			template:"<li @click='add'>{{counter}}</li>",
			data:function()
			{
				return data;
			},
			methods:{
				add:function()
				{
					this.counter++;
				}
			}
		})
		new Vue({
			el:"#root"
		})
	</script>
</body>

首先我要让组件共享数据,怎么做到呢?
首先template里面的data不能直接是对象,必须是函数,为了让函数返回相同的对象,我先在外面定义一个data对象,再在函数内返回data,那么导致他们的data是同一个data,就模拟出了实例的共享数据的情形。你会发现不管点击哪个组件。都会导致所有组件的数据的counter都会改变

因为他们改变的是同一个对象的counter属性。组件肯定是希望他互不干扰的,不然就会出现很多麻烦。所以组件的数据是不能共享的,不然就能通过其他组件改变他。所以我们需要用函数返回一个对象。这样每个对象是不一样的。很容易理解:{}!={};而data={};data===data,函数里面返回的是不同的地址,导致他返回的是不同的对象。每个组件只能改变自身的数据。所以我们这里只需要把data替换成{cuonter:0}即可。

DOM模板

主要是HTML标签有些元素只能包裹特定元素,比如table标签,select标签,ul标签,ol标签。还有些标签只能放在特定的标签里面,比如li标签,option标签,tr标签。
所以这类代码是会报错的:
<table><my-row></my-row></table>
因为my-row标签在html的渲染规则中是不能出现在table标签内部的。这时候要使用一个特殊的属性is。
<table><tr is="my-row"></tr></table>