一、自定义组件
1、全局自定义组件
我们在var vm = new Vue({});
的上面并列写上Vue.component('自定义组件名',{组件对象})
;来完成全局自定义组件的声明。示例代码如下:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'<h3>全局自定义组件</h3>' }); var vm = new Vue({ el:'#box' }); } </script> <div id="box"> <my-aaa></my-aaa> </div>
即我们在该自定义组件的组件对象的template
属性值当中设置该组件标签即将被替换成的html
标签字符串。即我们使用<my-aaa></my-aaa>
,则相当于是<h3>全局自定义组件</h3>
。
2、局部自定义组件
我们在var vm = new Vue({});
这个实例对象内部的属性components:{'自定义组件名':{该组件对象}}
的对象内部声明局部自定义组件。 示例代码如下所示:
<script> window.onload = function(){ var vm = new Vue({ el:'#box', components:{ 'my-bbb':{ template:'<h3>局部自定义组件</h3>' } } }); }; </script> <div id="box"> <my-bbb></my-bbb> </div>
全局自定义组件与局部自定义组件的用法大致都相似,下面主要以全局自定义组件为例来进行详细的说明。
3、自定义组件的数据属性
我们可以在自定义组件的组件对象的data
属性当中放置该组件的数据属性。但data
必须为函数的形式,并且该函数必须返回一个对象,我们在该返回的对象当中放置该组件的数据。示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'<h3>{{msg}}</h3>', data:function(){ return { msg:'哈哈!' }; } }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa></my-aaa> </div>
4、自定义组件的事件方法
我们可以在自定义组件对象的methods
当中定义该组件的事件方法,示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'<h3 @click="change">{{msg}}</h3>', data:function(){ return { msg:'哈哈!' }; }, methods:{ change:function(){ this.msg = 'change'; } } }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa></my-aaa> </div>
5、template属性值配合模板标签使用
如果我们自定义组件对象的template
属性值当中的html
标签比较多时,可以配合模板标签一起使用,把这些成堆的标签单独放在一起。示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc', data:function(){ return { msg:'哈哈!', arr:['apple','banana','pear','tomato'] }; }, methods:{ change:function(){ this.msg = 'change'; } } }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa></my-aaa> </div> <template id="ccc"> <div> <h3 @click="change">{{msg}}</h3> <ul> <li v-for="(val,index) in arr"> {{index}}----{{val}} </li> </ul> </div> </template>
显示结果如下所示,当点'哈哈!'
时,会变为change
。
vue1.x
的版本过渡到vue2.0
的版本的变化之一为,每个组件模板不再支持片段代码,即在vue2.0
当中的组件模板必须有一个根元素来包裹住所有的代码。即当上述代码更改为
<template id="ccc"> <h3 @click="change">{{msg}}</h3> <ul> <li v-for="(val,index) in arr"> {{index}}----{{val}} </li> </ul> </template>
则会报错component template should contain exactly one root element.
6、动态组件
我们在页面上放置一个固定名称的组件标签作为动态组件,如<component :is="a"></component>
,其中a
来自于vue
实例对象的data
属性,通过给a
赋予不同的自定义组件名,可以控制该动态组件当前的状态。示例代码如下所示:
<script> window.onload = function(){ var vm = new Vue({ el:'#box', data:{ a:'my-aaa' }, components:{ 'my-aaa':{ template:'<h3>我是组件aaa</h3>' }, 'my-bbb':{ template:'<h3>我是组件bbb</h3>' } } }); }; </script> <div id="box"> <button @click="a='my-bbb'">变为组件bbb</button> <button @click="a='my-aaa'">变为组件aaa</button> <component :is="a"></component> </div>
当页面完成加载之后,a
的初始值为'my-aaa'
,故此时页面上的动态组件代表<my-aaa></my-aaa>
,当我们点击变为组件bbb
按钮时,a
被赋值,此时页面的动态组件变为<my-bbb></my-bbb>
。但当点击变为组件aaa
按钮时,a
又被重新赋值,此时页面上的动态组件变回<my-aaa></my-aaa>
。
7、<slot>
标签的使用
slot
为位置、槽口的意思,作用为占位置。当自定义组件当中有一些特定的布局,不想被该组件当中的template
的代码完全覆盖时,可以采用slot
这个标签,该标签可以用来向组件内部插入一些内容,即我们在定义组件的时候留几个口子,由用户来决定插入的内容。单个插槽的示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc' }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa> <ul> <li>aaaa</li> <li>bbbb</li> </ul> </my-aaa> </div> <template id="ccc"> <div> <slot>只有在没有要分发的内容时才会显示</slot> <h3>自定义组件aaa</h3> </div> </template>
当我们在使用<my-aaa></my-aaa>
组件标签时,内部没有其他内容,则slot
标签对当中的文字内容会正常显示,但当该组件标签对当中有html
代码时,则slot
标签对当中的文字部分不会显示,并且在默认情况下,一对slot
标签对即代表该组件标签对当中全部的html
代码段。
在
vue2.0
当中,重名的插槽被移除,即同一模板当中重名的slot
已经被弃用,当一个插槽已经被渲染过了,那么就不能在同一模板的其他地方被再次渲染,如果要在不同位置渲染同一内容,可以用prop
来传递。
具名插槽的示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc' }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa> <ul slot="ul-slot1"> <li>aaaa</li> <li>bbbb</li> </ul> <ul slot="ul-slot2"> <li>cccc</li> <li>dddd</li> </ul> </my-aaa> </div> <template id="ccc"> <div> <slot name="ul-slot2"></slot> <h3>自定义组件aaa</h3> <slot name="ul-slot1"></slot> </div> </template>
二、组件间的通信
1、父子组件
我们可以在自定义组件对象当中的components
属性当中定义该组件对应的子组件。示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc', components:{ 'my-bbb':{ template:'<h4>{{msg}}</h4>', data:function(){ return { msg:'子组件bbb' }; } } } }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa></my-aaa> </div> <template id="ccc"> <div> <h3>自定义组件aaa</h3> <my-bbb></my-bbb> </div> </template>
2、子组件获取其父组件的数据
在默认情况下,子组件是无法访问到其父组件当中的数据的。如果希望子组件能获取到父组件的data
数据,使其能在子组件的template
的html
代码当中直接使用。则我们可以在给子组件的标签绑定上一个属性m
(该属性名可以任取),将父级的数据挂载到子组件的m
属性值上。然后我们在子组件对应的组件对象当中使用props:['m']
来得到该m
属性值,之后的可以把m
当作是来自于子组件对象当中的data
,即在子组件的template
当中可以用{{m}}
来获取,在methods
当中可以用this.m
来进行获取。示例代码如下所示:
<script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc', data:function(){ return { msg1:'嘻嘻!', msg2:'哈哈!', msg3:'呵呵!' }; }, components:{ 'my-bbb':{ template:'#ddd', props:['m1','m2','myM3'] } } }); var vm = new Vue({ el:'#box' }); }; </script> <div id="box"> <my-aaa></my-aaa> </div> <template id="ccc"> <div> <h3>自定义组件aaa</h3> <my-bbb :m1="msg1" :m2="msg2" :my-m3="msg3"></my-bbb> </div> </template> <template id="ddd"> <div> <h1>{{m1}}</h1> <h2>{{m2}}</h2> <h3>{{myM3}}</h3> </div> </template>
自定义属性名为
my-m3
,使用-
来进行连接,则我们在props
当中一律改为对应的驼峰命名下的myM3
。
在上述这种方式当中,子组件可以获取到父组件的数据,但是不允许直接对获取到的数据进行赋值操作。想要对获取到的数据进行赋值操作,同时达到更改父组件当中数据的目的,可以采取解决办法是,我们可以把父组件当中的数据包裹在一个对象当中来进行传递。示例代码如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="bower_components/vue/dist/vue.js"></script> <script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc', data:function(){ return { msg1:{ a:'呵呵!' }, }; }, components:{ 'my-bbb':{ template:'#ddd', props:['m1'], methods:{ change:function(){ this.m1.a = '哈哈!' } } } } }); var vm = new Vue({ el:'#box' }); }; </script> </head> <body> <div id="box"> <my-aaa></my-aaa> </div> <template id="ccc"> <div> <h3>{{msg1.a}}</h3> <my-bbb :m1="msg1"></my-bbb> </div> </template> <template id="ddd"> <div> <button @click="change()">change</button> <h3>{{m1.a}}</h3> </div> </template> </body> </html>
当点击按钮之后,变为:
3、父组件获取其子组件的数据
父组件想要获取子组件的数据,一般都是等子组件主动把自己的数据发送给父级。我们可以给子组件的某个dom
元素绑定一个事件,该事件函数体为this.$emit('自定义事件名',子组件的数据)
。即这个可以触发子组件身上的事件。示例代码如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="bower_components/vue/dist/vue.js"></script> <script> window.onload = function(){ Vue.component('my-aaa',{ template:'#ccc', data:function(){ return { msg1:'父组件的数据' }; }, methods:{ get:function(data){ this.msg1 = data; } }, components:{ 'my-bbb':{ template:'#ddd', data:function(){ return { msg2:'子组件的数据' }; }, methods:{ send:function(){ this.$emit('sendtofahter',this.msg2); } } } } }); var vm = new Vue({ el:'#box' }); }; </script> </head> <body> <div id="box"> <my-aaa></my-aaa> </div> <template id="ccc"> <div> <h3>{{msg1}}</h3> <my-bbb @sendtofahter="get"></my-bbb> </div> </template> <template id="ddd"> <div> <button @click="send()">send-to-father</button> <h3>{{msg2}}</h3> </div> </template> </body> </html>
当点击按钮之后,结果变为:
4、使用单一事件来管理组件间的通信
使用下面介绍的单一事件管理组件间通信可以替代之前介绍的两种父子组件之间的通信方式,还可以实现任意两个组件(如兄弟组件)之间的数据通信。
我们可以先在var vm = new Vue({});
并列的上方准备一个空的vue
实例对象,如var Event = new Vue();
。假设我们要实现A
组件发送数据给B
组件,我们可以给A
组件绑定一个事件,该事件函数体为Event.$emit('自定义事件名',A组件上的数据);
,然后我们再在B
组件的组件对象上的mounted
(该组件挂载完成之后触发执行的函数)函数体上写上Event.$on('对应的自定义事件名',function(data){})
;其中的data
即代表接收到的来自A
组件上的数据。示例代码如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="bower_components/vue/dist/vue.js"></script> <script> window.onload = function(){ var Event = new Vue(); Vue.component('my-aaa',{ template:'#ccc', data:function(){ return { msg1:'父组件的数据' }; }, mounted:function(){ Event.$on('sendtofahter',function(data){ this.msg1 = data; }.bind(this)); }, components:{ 'my-bbb':{ template:'#ddd', data:function(){ return { msg2:'子组件的数据' }; }, methods:{ send:function(){ Event.$emit('sendtofahter',this.msg2); } } } } }); var vm = new Vue({ el:'#box' }); }; </script> </head> <body> <div id="box"> <my-aaa></my-aaa> </div> <template id="ccc"> <div> <h3>{{msg1}}</h3> <my-bbb></my-bbb> </div> </template> <template id="ddd"> <div> <button @click="send()">send-to-father</button> <h3>{{msg2}}</h3> </div> </template> </body> </html>
上述代码可以实现与父组件获取其子组件当中的数据的示例代码一样的效果。下面给出两个兄弟组件之间通信的示例代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="bower_components/vue/dist/vue.js"></script> <script> window.onload = function(){ var Event = new Vue(); Vue.component('my-aaa',{ template:'#ccc', data:function(){ return { msg1:'兄弟组件aaa的数据' }; }, mounted:function(){ Event.$on('sendtobrother',function(data){ this.msg1 = data; }.bind(this)); } }); Vue.component('my-bbb',{ template:'#ddd', data:function(){ return { msg2:'兄弟组件bbb的数据' }; }, methods:{ send:function(){ Event.$emit('sendtobrother',this.msg2); } } }); var vm = new Vue({ el:'#box' }); }; </script> </head> <body> <div id="box"> <my-aaa></my-aaa> <my-bbb></my-bbb> </div> <template id="ccc"> <div> <h3>{{msg1}}</h3> </div> </template> <template id="ddd"> <div> <button @click="send()">send-to-brother</button> <h3>{{msg2}}</h3> </div> </template> </body> </html>
当我们点击按钮之后,显示的结果为: