在认识Vue中央事件总线之前,先来看看什么是组件传值
一、组件传值
- 父组件通过属性给子组件传值: 子组件的props接受数据(注意属性传值是单向的)
- 子组件通过调用父组件的方法给父组件传值:子组件的自定义事件中,用$emit触发事件调用父组件方法给父组件传值
因为通过属性传值是单向的,有时候我们需要子组件的data 数据需要交给父组件使用: 通过在子组件上定义自定义事件,在子组件中通过$emit 来触发事件;子组件的事件被触发并传参,事件处理函数可以接收到子组件的数据;事件绑定的事件处理函数在父节点上,故可在事件处理函数中用到子组件的数据值来修改父节点的数据。
//父组件中:
<my-search @myevent="handleEvent"></my-search>
//myevent是事子组件的自定义事件
//handleEvent是绑定的父组件的方法
子组件中:
在任意业务中触发事件:this.$emit("myevent","要给父组件传的数据")
-
多层组件传值:$listeners/$attrs
在不用状态管理vuex的时候,如何让GrandFather与Son通信,我们可以用可以emit一层一层的传递:会显得冗余。 vue2.4之后,提出$attrs、$listeners ,可以实现跨级组件通信。
$listeners官网解说:事件传递
$attrs官网解说:属性传递
在组件中绑定 可以把当前组件的自定义属性和方法传给子元素使用:
one组件:<two v-bind:xx="100" v-on:twoEvent="fn"></two>
two组件中:<three v-bind="$attrs" v-on="$listeners"></three>
three组件:可以访问two的 属性和触发事件: {{this.$attrs.xx}} this.$emit("twoEvent",20)
- $parent/$root、$children/$refs
这些功能都是有劣势或危险的场景的,官方建议我们尽量避开它们
$root: 访问根组件vm对象,所有的子组件都可以将这个实例作为一个全局 store 来访问或使用,现在有更好的技术vuex代替。
$parent:访问父组件对象,直接操作父组件的data数据,不需要再使用属性传值,但是容易出现渲染混乱之后只渲染一个的情况
$children:访问子组件对象数组,不能保证顺序,也不是响应式的
$refs:只会在组件渲染完成之后生效,并且它们不是响应式的。你应该避免在模板或计算属性中访问 $refs。
//在组件或者原生元素绑定ref属性(类似于id):
<myinput ref="myInput1"></myinput>
<input ref="myInput2"></input>
//在父组件中可以通过 this.$refs访问到它:
methods: {
focus: function () {
this.$refs.myInput2.focus()
}
}
-
sync修饰符
父组件属性通过.sync修饰,子组件this.$emit("update:绑定属性",修改的值)
//父组件
<template>
<div>
<h1>app----{{count}}</h1>
<Box :n.sync="count"></Box>
</div>
</template>
<script>
import Box from "./Box.vue"
export default {
data() {
return {
count: 20
}
},
components:{
Box
}
}
</script>
//子组件
<template>
<div>
<h1>box----{{n}}</h1>
<button @click="fn">儿子修改爸爸</button>
</div>
</template>
<script>
export default {
props:["n"],
methods:{
fn(){
this.$emit("update:n",this.n+1)
}
}
}
</script>
二、中央事件总线Bus
通过创建一个新的vm对象,专门统一注册事件,供所有组件共同操作,达到所有组件随意隔代传值的效果,全局的eventBus简单理解为在一个文件创建一个新的vue实例然后暴露出去, 使用的时候import这个模块进来即可
第一步:创建一个bus.js文件通过export default导出
//vue-bus.js文件
const install = function (Vue) {
const Bus = new Vue({
methods: {
emit(event, ...args) {
this.$emit(event, ...args);
},
on(event, callback) {
this.$on(event, callback);
},
off(event, callback) {
this.$off(event, callback);
}
}
});
Vue.prototype.$bus=Bus;//由于这个新的vm放在与界面绑定的那个vm的原型上,因此页面上的所有组件都能通过this.$bus访问这个新vm对象
};
export default install;
第二步:创建一个main.js文件,使用import导出
//main.js文件
import VueBus from './vue-bus'
Vue.use(VueBus);
//组件文件中:
任意业务中都可以通过调用来绑定事件,触发事件并传值,和销毁事件
this.$bus.on(event,callback)
this.$bus.off(event,callback)
this.$bus.emit(event, ...args)
示例:
组件1:
this.$bus.on('changedFormObject',(val) =>{
//接受并处理传过来的值:val
this.msg = val;
});
组件2:
this.$bus.emit('changedFormObject',this.inputValue);//把组件2的data中的给inputValue值传给组件1