一、中央事件总线bus
在 Vue.js 2.x 中,推荐使用一个空的 Vue 实例作为中央事件总线(bus)。
示例代码如下:
<body>
<div id="app">
{{ message }}
<component-a></component-a>
</div>
<template id="tmp">
<button @click="handleEvent">传递事件</button>
</template>
<script type="text/javascript" src="../js/vue-2.4.0.js" ></script>
<script>
var bus = new Vue(); //定义一个空的vue实例bus
Vue.component('component-a',{
template: '#tmp',
methods: {
handleEvent:function () {
bus.$emit('on-message','来自组件componet-a的内容'); //通过bus.$emit向父组件传参
}
}
});
var vm = new Vue({
el: "#app",
data: {
message: ''
},
mounted:function () {
var _this = this; //把 this 的实例(vm)赋给_this
bus.$on('on-message',function (msg){ //通过$on来接受子组件的信息
_this.message = msg; //这里如果继续使用this表示的是bus的实例
});
}
})
</script>
首先创建一个名为 bus 的空实例,然后全局定义一个组件,最后创建 Vue 实例 app,在 app初始化时,也就是在生命周期 mounted 钩子函数里监听了来自 bus 的事件 on-message,而在组件 component-a 中,点击按钮会通过 bus 把事件 on-message 发出去,此时 app 就会接收到来自 buss 的事件,进而在回调里完成自己的业务逻辑。
二、父链
在子组件中,使用 this.$ parent 可以直接访问该组件的父实例或组件,父组件也可以通过 this.$children 访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。示例代码如下:
<div id="app">
<p v-text="message"></p>
<component-a></component-a>
</div>
<template id="tmp">
<button @click="handleEvent">通过父链直接修改数据</button>
</template>
<script type="text/javascript" src="../js/vue-2.4.0.js" ></script>
<script>
Vue.component('component-a',{
template: '#tmp',
methods: {
handleEvent: function () {
this.$parent.message = '来自组件component-a的内容';
}
}
});
var vm = new Vue({
el: "#app",
data: {
message: ''
}
})
</script>
尽管 Vue 允许这样操作,但在业务中,子组件应该尽可能地避免依赖父组件的数据,更不应该主动修改它的数据,因为这样使得父子组件紧耦合,只看父组件,很难理解父组件的状态。父组件最好还是通过 props 和 $emit 来通信。
三、子组件索引
当子组件较多时,通过 this.$children 来一一遍历出我们需要的一个组件实例是比较困难的,尤其是组件动态渲染时,它们的序列是不固定的。Vue 提供了子组件索引的方法,用特殊的属性 ref 来为子组件指定一个索引名称,示例代码如下:
<div id="app">
<p v-text="message"></p>
<component-a></component-a>
</div>
<template id="tmp">
<button @click="handleEvent">通过父链直接修改数据</button>
</template>
<script type="text/javascript" src="../js/vue-2.4.0.js" ></script>
<script>
Vue.component('component-a',{
template: '#tmp',
methods: {
handleEvent: function () {
this.$parent.message = '来自组件component-a的内容';
}
}
});
var vm = new Vue({
el: "#app",
data: {
message: ''
}
})
</script>
在父组件模板中,子组件标签上使用 ref 指定一个名称,并在父组件内通过 this.$refs 来访问指定名称的子组件。 $refs只在组件渲染完成后才填充,并且它是非响应式。它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用 $refs。