7

总线机制

非父子之间传值,可以采用发布订阅模式,这种模式在 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去调用MutationsMutations中放的是一个个同步的修改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 给删除了。
}

uccs
756 声望88 粉丝

3年 gis 开发,wx:ttxbg210604