组件系统是vue的一个重要的概念。他可以让我们使用独立的,可复用的小组件来构建大的复杂的应用,任何应用都可以看作是组件树。组件可以看做是自定义的Html代码。可扩展的html,封装可重用的html。

使用组件的使用分为三步

创建组件构造器,调用Vue.extend()创建,这是Vue构造器的扩展。他有个选项对象。选项对象有个template属性,定义组件要渲染的html

注册组件 ,Vue.compontent()注册

使用组件(在Vue实例的作用范围内使用组件,必须挂载在实例下,否则不生效)

举例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
     </head>
    <body>
        <div id="app1">
            <my-component></my-component>
        </div>
         <div id="app2">
            <my-component></my-component>
        </div>
    </body>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js">
    </script>
    <script>
        var mycomponent = Vue.extend({
            template:'<div>啊啊啊,苍天大地</div>'
        }); 
         var app1 = new Vue({
            el: '#app1',
            components : {'my-component' :mycomponent}
        })
        //以下就没效果
         var app1 = new Vue({
            el: '#app2',
         })
    </script>

</html>
 my-component是注册在#app1下的。所以不能在其他Vue实例下使用。
在组件中使用其他组件就构成了父子组件关系。
正常组件 使用时,<></>标签一般写在<body>内部(view层)。
但是父子组件情况是:子组件<></>出现在使用父组件时model层,
举例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
table tr td{
    border:1px solid gray;
    padding:10px;
     
}
table{
    border-collapse:collapse;
    width:800px;
    table-layout:fixed;
}
tr.firstLine{
    background-color: lightGray;
}
</style>
<body>
<!--view层  -->
    <div id="app">
  <parent-component></parent-component>
    </div>
</body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js">
</script>
<script >
/* Model层 */
var exampleData ={
        exchange: 6.4,
        rmb:0 
}
//创建子组件
var Child =Vue.extend({
    template:'<p>这是个子组件</p>'
})
//创建父组件
var Parent =Vue.extend({
    //在Parent组件里使用  <child-component>标签
    template:'<p>这是个父组件  <child-component></child-component></p>',
    //局部注册子组件
    components:{
        'child-component':Child
    }
})
//全局注册下Parent组件
Vue.component('parent-component',Parent)
new Vue({
 //...
 el:'#app'
  
})
</script>
</html>

 

结果如下:

理解下:截取代码
1,//局部注册子组件
    components:{
        'child-component':Child
    }
这是在子组件注册到父组件中,并将子组件的标签设置为 child-component

2,template:'<p>这是个父组件  <child-component></child-component></p>',
这就是说 在父组件内以标签形式使用子组件。在页面用标签渲染父组件的内容,同时子组件的内容也被渲染出来。

上面的例子,子组件是在父组件里注册的,它只能在父组件里的
template里使用。
下面示范下两种错误的使用子组件的例子
错误1:
<div id="app">
  		<parent-component>
 		   <child-component></child-component>		
  		</parent-component>
	</div>

  解释下为什么无效呢?

当子组件注册到父组件下时候,Vue.js会编译好父组件的模板,模板的内容已经决定了父组件即将要渲染的HTML

<parent-component>
..... </parent-component>相当于他的子标签只能当做普通的HMTL执行,他不是普通的html标签,就会被忽略。
上面注册有点繁琐:
Vue简化了上面的步骤,如下举例子:
Vue.component('parent-component',{template:'<p>这是个父组件呢 <child-component></child-component></p>'})

第一个参数是标签名称,第二个是选项对象,使用选项对象的template属性定义组件模板。
这种方法Vue在背后自动调用Vue.extend()
但是呢,尽管上面简化了步骤,还是得在template里拼接html,依然麻烦。
Vue提供了两种方式将定义在js里的html模板分离出来。script标签和template标签
1.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
table tr td{
    border:1px solid gray;
    padding:10px;
     
}
table{
    border-collapse:collapse;
    width:800px;
    table-layout:fixed;
}
tr.firstLine{
    background-color: lightGray;
}
</style>
<body>
<!--view层  -->
	<div id="app">
  		<my-component>
  		</my-component>  		
	</div>
	<script type="text/x-template" id="my-component">
        <div>This is my-component</div>
    </script>
</body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js">
</script>
<script >
/* Model层 */
//全局注册下Parent组件
Vue.component('my-component',{
	//template选项现在不是html元素,而是一个id,Vue.js根据这id查找对应的元素,然后把这个元素内的html作为模板
	//进行编译
	template:'#my-component'
})
new Vue({
 //...
 el:'#app'
  
})
</script>
</html>

  2,

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
table tr td{
    border:1px solid gray;
    padding:10px;
     
}
table{
    border-collapse:collapse;
    width:800px;
    table-layout:fixed;
}
tr.firstLine{
    background-color: lightGray;
}
</style>
<body>
<!--view层  -->
	<div id="app">
  		<my-component>
  		</my-component>  		
	</div>
	<template  id="my-component">
        <div>This is my-component</div>
    </template>
</body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js">
</script>
<script >
/* Model层 */
//全局注册下Parent组件
Vue.component('my-component',{
	//template选项现在不是html元素,而是一个id,Vue.js根据这id查找对应的元素,然后把这个元素内的html作为模板
	//进行编译
	template:'#my-component'
})
new Vue({
 //...
 el:'#app'
  
})
</script>
</html>

  上面两种效果近似。重点看script和template标签的差别。

传入Vue构造器的多数选项也可以在Vue.compontent()和Vue.extend()中使用。不过有两个例外。data和el选项例外。

Vue.js规定,定义组件的选项时,data和el选项必须使用函数。

 不然会报错。但是测试下如下代码没报错。为什么?

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
table tr td{
    border:1px solid gray;
    padding:10px;
     
}
table{
    border-collapse:collapse;
    width:800px;
    table-layout:fixed;
}
tr.firstLine{
    background-color: lightGray;
}
</style>
<body>
<!--view层  -->
	<div id="app">
  		<my-component>
  		</my-component>  		
	</div>
	<template  id="my-component">
        <div>This is my-component</div>
    </template>
</body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js">
</script>
<script >
/* Model层 */
//全局注册下Parent组件
Vue.component('my-component',{
	template:'#my-component',
	data:{
		a:1
	}
})
new Vue({
 //...
 el:'#app'
  
})
</script>
</html>

 

  如果让组件的data选项指向一个对象,意味着所有的组件共用一个data。应该使用一个函数作为data选项,让这个函数返回一个新对象。

引子:虽然Vue常用于双向绑定,互相影响,但是有单向绑定怎么办呢?父组件影响子组件,子组件修改的影响不了父组件。

引出props选项:

props基础:

组件的作用域都是孤立的,这意味着不能且不应该直接在子组件的模板里直接用父组件的数据。用prop把数据传给子组件。

<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>


<body>
<!--view层  -->
	<div id="app">
  		<my-component v-bind:my-name="name" v-bind:my-age="age">
  		</my-component>  		
	</div>
	<template  id="mycomponent">
		<table>
			<tr>
				<th colspan="2">
					子组件数据
				</th>
			</tr>
			<tr>
				<td>my name</td>
				<td>{{ myName }}</td>
			</tr>
			<tr>
				<td>my age</td>
				<td>{{ myAge }}</td>
			</tr>
		</table>  
	  </template>
</body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js">
</script>
<script >
/* Model层 */


var vm =new Vue({
 //...
 el:'#app',
 data:{
	 name:'小章',
	 age:23
 },
components:{'my-component':{
	template:'#mycomponent',
	props:['myName','myAge']
}
 }
  
})
</script>

</html>

  注意一点:

子组件的props选项时候需要是驼峰命名法。对应的HTML不分大小写,用-隔离。像上面用法。对应起来。 

props单向影响联系。

下面例子演示影响修改父组件数据影响。