Vue 中非父子组件间的传值
总线机制
非父子之间传值,可以采用发布订阅模式,这种模式在 Vue 中被称为总线机制,或者叫做Bus / 发布订阅模式 / 观察者模式
<div id="root">
<child content="Dell"></child>
<child content="Lee"></child>
</div>
Vue.prototype.bus = new Vue() //挂载 bus 属性
Vue.component('child', {
data(){
return {
selfContent: this.content
}
},
props: {
content:String
},
template: '<div @click="handleChildClick">{{selfContent}}</div>',
methods: {
handleChildClick() {
this.bus.$emit('change',this.selfContent) // 发布
}
},
mounted(){
this.bus.$on('change',(msg)=>{ //订阅,这里会被执行两次
this.selfContent = msg
})
}
})
let vm = new Vue({
el: '#root'
})
Vue.prototype.bus = new Vue()这句话的意思是,在 Vue 的prototype挂载了一个bus属性,这个属性指向 Vue 的实例,只要我们之后调用 Vue 或者new Vue时,每个组件都会有一个bus属性,因为以后不管是 Vue 的属性还是 Vue 的实例,都是通过 Vue 来创建的,而我在 Vue 的prototype上挂载了一个bus的属性。
组件被挂载之前会执行mounted钩子函数,所以可以在mounted中对change事件进行监听。
this.bus.$on()那边会被执行两次,原因是什么呢?因为在一个child组件里面,触发事件的时候,外面两个child的组件都进行了同一个事件的监听,所以两个child的组件都会执行一遍this.bus.$on()
Vuex
两个兄弟组件之间公共的父组件,那么它们就没法通过一个公用的父组件来进行数据的中转,要实现这两个页面组件的数据通信应该怎么办呢?
vuex是 Vue 官方推荐的数据框架,在 Vue 的大型项目开发之中,Vue 只能承担视图层的内容,而当我们涉及到大量数据传递的时候,往往都需要一个数据框架进行辅助,Vue 之中这个数据框架就是vuex
看上图vuex指的是整个图中虚线部分的内容。
那vuex是什么呢?当我们的一个项目之中,比如说多个组件之间进行复杂的数据传递很困难的时候,如果能把这些公用的数据,放在一个公共的存储空间去存储,然后某一个组件改变了这个公共的数据,其他的组件就能感知到,不就可以了吗。vuex的设计理念就是这样的。
回到上图,右侧虚线那块的图就是公用数据存储区域,我们可以把这个区域理解成store仓库,这个仓库是由几部分组成的:
State:它是干嘛用的呢?我们所有的公用数据都存放在State当中,那组件想要用公用的数据,直接去调用State就可以了Actions:有些时候想要改变State中的数据,但是不能让组件直接改变State中的数据,必须走一个流程。这里有一些异步操作,将这些异步操作放在Actions,或者一些复杂的同步操作(批量),也可以放在Actions中Mutations:组件想要改变数据先去调用Actions,通过Actions去调用Mutations,Mutations中放的是一个个同步的修改State的方法
结论:只有通过Mutations才能改变State中公用数据的值,这一步也不是绝对的,有时候可以略过Actions这一步,让组件直接调用Mutations修改State中的数据。这里需要注意的是组件调用Actions是通过Dispatch方法,而组件直接调用Actions或者Actions调用Mutations是通过Commit方法。
其实它就是一个单向数据的改变流程。
具体看下代码是怎么实现的:
export default new Vuex.store({
state: {
name: '天天'
},
actions: {
changeName (ctx, name) { //ctx 是上下文
ctx.commit('changeName', name) //通过 commit 调用 mutations 去改变 state,这个 changeName 可以自己随便起名字保证和 mutations 中一样即可
}
},
mutations: {
changeName (state, name) {
state.name = name
}
}
})
组件需要使用就可以直接这样使用this.$store.state.name
当其他地方需要修改name时,可以这样写
handleNameClick (name) {
this.$store.dispatch('changeName', name) //派发一个名字叫 changeName 的 Actions,并把 name 传过去
}
这边我在改变state时没有任何异步操作,而且这个操作也非常简单,这个时候组件其实没有必要去调用Actions做这个转发,组件可以直接去调用mutations。
handleNameClick (name) {
this.$store.commit('changeName', name) //派发一个名字叫 changeName 的 mutation,并把 name 传递过去。所以上面的 store 里可以把 Actions 给删除了。
}
浙公网安备 33010602011771号