组件是可复用的Vue实例,一个组件本质上是一个拥有预定义选项的一个Vue实例,组件和组件之间通过一些属性进行联系。
组件有两种注册方式,分别是全局注册和局部注册,前者通过Vue.component()注册,后者是在创建Vue实例的时候在components属性里指定,例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="vue.js"></script> </head> <body> <div id="app"> <child title="Hello Wrold"></child> <hello></hello> <button @click="test">测试</button> </div> <script> Vue.component('child',{ //全局注册 props:['title'], template:"<p>{{title}}</p>" }) var app = new Vue({ el:'#app', components:{ hello:{template:'<p>Hello Vue</p>'} //局部组件 }, methods:{ test:function(){ console.log(this.$children) console.log(this.$children[1].$parent ===this) } } }) </script> </body> </html>
渲染DOM为:
其中Hello World是全局注册的组件渲染出来的,而Hello Vue是局部组件渲染出来的。
我们在测试按钮上绑定了一个事件,点击按钮后输出如下:
可以看到Vue实例的$children属性是个数组,对应的是当前实例引用的所有组件的实例,其中$children[0]是全局组件child的实例,而children[1]是局部组件hello的实例。
而this.$children[1].$parent ===this输出为true则表示对于组件实例来说,它的$parent指向的父组件实例,也就是例子里的根组件实例。
Vue内部就是通过$children和$parent属性实现了父组件和子组件之间的关联的。
组件是可以无限复用的,比如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="vue.js"></script> </head> <body> <div id="app"> <child title="Hello Wrold"></child> <child title="Hello Vue"></child> <child title="Hello Rose"></child> </div> <script> Vue.component('child',{ props:['title'], template:"<p>{{title}}</p>" }) var app = new Vue({el:'#app'}) </script> </body> </html>
渲染为:
注:对于组件来说,需要把data属性设为一个函数,内部返回一个数据对象,因为如果只返回一个对象,当组件复用时,不同的组件引用的data为同一个对象,这点和根Vue实例不同的,可以看官网的例子:点我点我
例1:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="vue.js"></script> </head> <body> <div id="app"> <child ></child> </div> <script> Vue.component('child',{ data:{title:"Hello Vue"}, template:"<p>{{title}}</p>" }) var app = new Vue({el:'#app'}) </script> </body> </html>
运行时浏览器报错了,如下:
报错的内部实现:Vue注册组件时会先执行Vue.extend(),然后执行mergeOptions合并一些属性,执行到data属性的合并策略时会做判断,如下:
strats.data = function ( //data的合并策略 第1196行 parentVal, childVal, vm ) { if (!vm) { //如果vm不存在,对于组件来说是不存在的 if (childVal && typeof childVal !== 'function') { //如果值不是一个函数,则报错 "development" !== 'production' && warn( 'The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm ); return parentVal } r