组件之间通讯能够用下图表示:app
组件关系可分为父子组件通讯、兄弟组件通讯、跨级组件通讯。函数
1、自定义事件this
当子组件须要向父组件传递数据时,就要用到自定义事件。spa
子组件用$emit ()来触发事件,父组件用$on()来监昕子组件的事件。双向绑定
父组件能够直接在子组件的自定义标签上使用v-on 来监昕子组件触发的自定义事件,如:code
<div id="app9"> <p>总数:{{total}}</p> <my-component9 @add="getTotal" @cut="getTotal"></my-component9> </div>
Vue.component('my-component9',{ template: '<div>' + ' <button @click="increase">+1</button>' + ' <button @click="reduce">-1</button>' + '</div>', data: function(){ return { count: 0 } }, methods:{ increase: function(){ this.count++; this.$emit('add',this.count) //广播的事件名和数据 }, reduce: function(){ this.count--; this.$emit('cut',this.count) //广播的事件名和数据 } } }); var app9 = new Vue({ el: '#app9', data:{ total: 0 }, methods:{ getTotal: function(count){ this.total = count; } } });
2、使用v-modelcomponent
Vue2 .x 能够在自定义组件上使用v-model 指令,直接看一个事例:blog
<div id="app10"> <p>总数:{{total}}</p> <my-component10 v-model="total"></my-component10> //这个地方v-model实际是一个语法糖,能够直接理解为接收到广播input里面的数据(this.total=count)。 </div>
Vue.component('my-component10',{ template: '<div>' + '<button @click="increase">+1</button>' + '<button @click="reduce">-1</button>' + '</div>', data: function(){ return { count: 0 } }, methods:{ increase: function(){ this.count++; this.$emit('input',this.count) //注意这个地方,广播的事件名称为特殊的input }, reduce: function(){ this.count--; this.$emit('input',this.count) //注意这个地方,广播的事件名称为特殊的input } } }); var app10 = new Vue({ el: '#app10', data:{ total: 0 } });
v-model 还能够用来建立自定义的表单输入组件, 进行数据双向绑定,例如:递归
<div id="app11"> <p>总数:{{total}}</p> <my-component11 v-model="total"></my-component11> <button @click="reduce">-1</button> </div>
Vue.component('my-component11', { props: ['value'], //使用v-model的表单组件时,父组件经过value来进行传值 template: '<input :value="value" @input="updateValue">', methods: { updateValue: function(event){ this.$emit('input', event.target.value); } } }); var app11 = new Vue({ el: '#app11', data:{ total: 0 }, methods:{ reduce: function(){ this.total-- } } });
父组件的total发生变化时,会经过传递value值,影响子组件input中的value值,而子组件改变本身input中的value值,又会广播给父组件,影响父组件中的total值。索引
实现这样一个具备双向绑定的v -model 组件要知足下面两个要求:
•接收一个value 属性。
• 在有新的value 时触发input 事件。
3、非父子组件通讯
在Vue . 2.x 中, 推荐使用一个空的Vue 实例做为中央事件总线( bu s ),也就是一个中介。
直接看一个事例:
<div id="app12"> <p>{{message}}</p> <my-component12></my-component12> </div>
var bus = new Vue(); Vue.component('my-component12',{ template: '<button @click="updateMessage">传递事件信息</button>', methods: { updateMessage: function(){ bus.$emit('updateMessage','更新个人组件信息'); //利用中介bus传播事件 } } }); var app12 = new Vue({ el: '#app12', data:{ message: '' }, mounted: function(){ var _this = this; //这一步赋值必须有 bus.$on('updateMessage',function(data){ //利用中介bus接收事件 _this.message = data; }) } });
在app 初始化时,也就是在生命周期mounted 钩子函数里监听了来自bus 的事件updateMessage(mounted挂载这一步至关于在两个组件直间提早安排了一个中介,当两个组件通讯时,就能够经过该中介相互传递消息了) ,
而在组件my-component12中,点击按钮会经过bus 把事件updateMessage发出去,此时app 就会接收到来自bus 的事件,进而在回调里完成本身的业务逻辑。
这种方法巧妙而轻量地实现了任何组件间的通讯,包括父子、兄弟、跨级,并且Vue 1.x 和Vue 2.x 都适用。
4、父链与子组件索引
除了中央事件总线bus 外,还有两种方法能够实现组件间通讯:父链和子组件索引。
在子组件中,使用this.$parent 能够直接访问该组件的父实例或组件,父组件也能够经过this.$children 访问它全部的子组件,并且能够递归向上或向下无线访问, 直到根实例或最内层的组件。
4.1父链
<div id="app13"> <p>{{message}}</p> <my-component13></my-component13> </div>
Vue.component('my-component13',{ template: '<button @click="updateMessage">经过父链直接修改数据</button>', methods: { updateMessage: function(){ this.$parent.message = '来自组件my-component13的内容' //经过this.$parent直接修改父组件的内容 } } }); var app13 = new Vue({ el: '#app13', data:{ message: '' } });
尽管V ue 容许这样操做,但在业务中, 子组件应该尽量地避免依赖父组件的数据,更不该该去主动修改它的数据,由于这样使得父子组件紧藕合,理想状况下,只有组件本身能修改它的状态。
4.2 子组件索引
当子组件较多时, 经过this.$children 来一一遍历出咱们须要的一个组件实例是比较困难的,尤为是组件动态渲染时,它们的序列是不固定的。Vue 提供了子组件索引的方法,用特殊的属性ref来为子组件指定一个索引名称。
<div id="app14"> <p>{{message}}</p> <my-component14 ref="com14"></my-component14> <button @click="handleRef">经过ref获取子组件实例</button> </div>
Vue.component('my-component14',{ template: '<div>子组件</div>', data: function(){ return { message: '子组件内容' } } }); var app14 = new Vue({ el: '#app14', data:{ message: '' }, methods: { handleRef: function(){ this.message = this.$refs.com14.message; //经过$refs获取子组件实例 } } });
在父组件模板中,子组件标签上使用ref 指定一个名称,井在父组件内经过this.$refs 来访问指定名称的子组件。
$refs 只在组件渲染完成后才填充,而且它是非响应式的. 它仅仅做为一个直接访问子组件的应急方案,应当尽可能避免在模板或计算属性中使用$refs。