一、父子组件间-自定义事件
子组件用$emit()
来触发事件,父组件用$on
来监听子组件的事件。
//父组件代码
<my-component
@increase="handleGetTotal"
></my-component>
//父组件函数代码
handleGetTotal:function(total){
this.total=total
}
//子组件代码
<div>
<button @click="handleIncrease">+1</button>
</div>
//子组件函数代码
handleIncrease:function(){
this.counter++;
this.$emit('increase',this.counter);
}
子组件通过click事件修改自己的counter值,并将得到的counter通过自定义事件increase传递给父组件,作为handleGetTotal函数的参数,并赋值给app的total变量。
二、父子组件间-使用v-model
在自定义组件上使用v-model实现双向绑定。$emit()的事件名是特殊的”input”。
//父组件
<my-component v-model="total"></my-component>
<button @click="handleReduce">-1</button>
//父组件函数
handleReduce:function(){
this.total--;
}
//子组件
Vue.component('my-component',{
props:['value'],
template:'<input :value="value" @input="updateValue">',
methods:{
updateValue:function(event){
this.$emit('input',event.target.value);
}
}
});
父组件通过v-model将total值传入子组件,子组件通过props中的value接收total值并通过v-bind显示在input元素中;子组件自定义input事件,将在input元素中输入的值通过$emit()传递给父组件的total。
三、任意组件间-中央事件总线(bus)
任意组件(包括父子、兄弟、跨级)间的通信推荐使用一个空的Vue实例作为中央事件总线(bus),也就是一个中介。
//html
<div id="app">
{{message}}
<component-a></component-a>
</div>
//js
var bus=new Vue();//定义一个空Vue实例作为中央事件总线
Vue.component('component-a',{
template:'<button @click="handleEvent">传递事件</button>',
methods:{
handleEvent:function(){
bus.$emit('on-message','来自组件component-a的内容');
}
}
});
var app=new Vue({
el:'#app',
data:{
message:'hello init'
},
mounted:function(){
var _this=this;
//在实例初始化时,监听来自bus实例的事件
bus.$on('on-message',function(msg){
_this.message=msg;
})
}
});
子组件通过$emit()
给bus空实例添加了一个on-message自定义事件,父组件通过bus.$on()
监听这个on-message事件。
四、祖孙组件间-父链
在子组件中使用this.$parent
可以直接访问该组件的父实例或组件,父组件也可以通过this.$children
访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。
//html
<div id="app">
{{message}}
<component-a></component-a>
</div>
//js
Vue.component('component-a',{
template:'<button @click="handleEvent">传递事件</button>',
methods:{
handleEvent:function(){
//访问到父链后,可以做任何操作,比如直接修改数据
this.$parent.message='来自组件component-a的内容';
}
}
});
var app=new Vue({
el:'#app',
data:{
message:'hello init'
}
});
注意,在业务中子组件应尽量避免依赖父组件的数据,更不该主动修改它的数据,因为这样使得父子组件紧耦合。父子组件最好还是通过props和$emit()
来通信。
五、父子组件间-子组件索引
当子组件较多时,可以使用子组件索引的方法,即用特殊的属性ref来为子组件指定一个索引名称。
在父组件模板中,子组件标签上使用ref指定一个名称,并在父组件内通过this.$refs
来访问指定名称的子组件。
//html
<div id="app">
<div>{{msg}}</div>
<button @click="handleRef">通过ref获取子组件实例</button>
<component-a ref="comA"></component-a>
</div>
//js
Vue.component('component-a',{
template:'<div>子组件</div>',
data:function(){
return{
message:'子组件内容'
}
}
});
var app=new Vue({
el:'#app',
data:{
msg:'hello init'
},
methods:{
handleRef:function(){
var msg=this.$refs.comA.message;
this.msg=msg;
}
}
});
注意,$refs
只在组件渲染完成后才填充,并且它是非响应式的。它仅仅作为一个直接访问子组件的应急方案,应当避免在木板或计算属性中使用它。
——阅读《Vue.js实战》第7章
