手撕Vuex-添加全局$store

发布时间 2023-10-28 14:50:02作者: BNTang

经过上一篇的介绍,了解到了 Vuex 的实现本质就是一个插件,所以要做的事情就是实现这个插件的代码编写即可。

本篇文章主要是实现一个全局的 $store,这个 $store 是挂载在 Vue 的原型上的,所以在任何一个组件当中都可以通过 this.$store 访问到。

我们先来看看 Vue 官方的,我们分别在 App.vue, HelloWorld.vue 中打印 this.$store,看看能不能访问到。

mounted() {
  console.log(this.$store);
}

image-20231028122125928

可以看到都访问到了,那么我们就可以开始实现了。

官方开发插件文档:https://cn.vuejs.org/guide/reusability/plugins.html

我这里直接上代码,创建一个 Nuex.js 文件,在文件中先简单的暴露一个 install 方法。

这个 install 方法是 Vue.use() 调用的,所以在这个方法中可以接收到 Vue 的实例,然后在这个方法中实现我们的逻辑。

在使用 Vuex 的时候需要传递一个 store 对象,这个 store 对象就是我们的仓库,所以我们还需要在 Nuex.js 文件中暴露一个 Store 属性,这个属性的取值是一个类。

最终的代码如下:

/**
 * install方法会在外界调用Vue.use的时候执行
 * 并且在执行的时候会把Vue实例和一些额外的参数传递给我们
 * @param Vue Vue实例
 * @param options 额外的参数
 */
const install = (Vue, options) => {
}

export default {
    install
}

这样我们的插件就创建完毕了,接下来就是在 install 方法中实现我们的逻辑。给每一个Vue实例都添加一个 $store 属性。

在Vue中有一个名称叫做mixin方法,这个方法会在创建每一个Vue实例的时候执行,所以我们可以通过mixin方法给每一个Vue实例添加 $store 属性。

紧接着继续改写我们的代码,调用 Vue.mixin 方法重写 beforeCreate 方法,这个方法会在每一个组件创建的时候执行。

具体的核心逻辑我这里先不写,我先在 beforeCreate 方法中打印一下组件的一些参数信息。

image-20231028142241388

打开浏览器控制台,运行结果如下:

image-20231028142432851

可以看到在 beforeCreate 方法中打印了三次,Vue 实例化的时候会先实例化根组件,然后在实例化根组件的时候会先实例化子组件,所以会打印三次。(Vue,App, HelloWorld)

如何验证这个结论呢那么就是分别打印一下实例化组件的名称,根组件还没有添加 name 属性,先给我们的根组件也取一个名字,叫做 root:

image-20231028142757748

在更改下 beforeCreate 方法打印的属性值为 $options.name 即可:

image-20231028142930627

返回浏览器控制台观察输出结果:

image-20231028143013047

输出的内容和我们的结论是一致的,知道了实例化的过程之后,接下来就是完善核心逻辑即可,我们知道在实例化过程中,首先实例化的是根组件,然后在实例化根组件的时候会先实例化子组件,所以我们可以在实例化根组件的时候给根组件添加一个 $store 属性,然后在实例化子组件的时候直接从父组件中取出 $store 属性赋值给子组件即可。

在根组件中有一个 store,只要将这个 store 赋值给 $store 即可,那么在子组件中就可以通过 this.$store 访问到了。

有了思路之后,我们就可以开始编写代码了,最终实现的代码如下:

beforeCreate() {
    /*
    如果是根组件, 那么默认就有store
    我们只需要将store变成$store即可
    */
    if (this.$options && this.$options.store) {
        this.$store = this.$options.store;
    } else {
        /*
        如果不是根组件, 那么默认没有store
        我们只需要将它父组件的$store赋值给它即可
        */
        this.$store = this.$parent.$store;
    }
}

然后在将之前组件中访问 this.$store 的代码放开(取消注释):

image-20231028144203188

然后重新运行项目,可以看到可以访问到 this.$store

image-20231028144109223

到这里添加全局 $store 的代码就完成了。