总线机制
非父子之间传值,可以采用发布订阅模式,这种模式在 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 给删除了。
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。