这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战
一,前言
上一篇,介绍了 vuex 的基本用法,主要包含以下几个点:
- vuex 项目创建;
- vuex 工作流程介绍;
- vuex 的基本使用介绍;
本篇,继续介绍 vuex 插件安装 install 逻辑;
二,vuex 插件安装逻辑的实现
1,前文回顾
上一篇,在介绍 vuex 的基本用法前,安装并配置 vuex 插件,导出 store 实例:
// src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
// 注册 vuex 插件:内部会调用 Vuex 中的 install 方法
Vue.use(Vuex);
// 实例化容器容器:Vuex.Store
const store = new Vuex.Store({
...
});
// 导出 store 实例,传入根组件
export default store;
当new Vue
初始化时,将 store 容器实例注入到 vue 根实例中:
// src/main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store/index' // 引入 store 实例
new Vue({
store,// 将 store 实例注入到 vue 中
render: h => h(App),
}).$mount('#app');
vuex 的基本使用:
<template>
<div id="app">
商品数量: {{this.$store.state.num}} 个<br>
商品单价: 10 元<br>
订单金额: {{this.$store.getters.getPrice}} 元<br>
<button @click="$store.commit('changeNum',5)">同步更新:数量+5</button>
<button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button>
</div>
</template>
从 Vuex 的使用方式进行简单分析:
- Vuex 是一个对象;
- Vuex 中包含了一个 Store 类;
- Vuex 内部有一个 install 安装方法,当执行
Vue.use(Vuex)
时被执行; - Vuex 与 VueRouter 相似,插件安装时向所有组件混入(共享)store 容器实例;
2,创建 vuex 插件
基于以上 Vuex 插件特点,创建 vuex 目录和入口文件 src/vuex/index.js,其中包含 Store 类和 install 方法并导出:
// src/vuex/index.js
// 容器的初始化
class Store {
}
// 插件安装逻辑:当Vue.use(Vuex)时执行
const install =()=>{
}
export default {
Store,
install
}
3,模块化设计
- Store 类的作用:容器的初始化,产生一个 store 容器实例;
- install 方法的作用:插件安装逻辑;当
Vue.use(Vuex)
时被调用; - src/vuex/index.js 文件的作用:作为 vuex 插件入口,导出方法供外部调用;
Vuex 的模块化设计:将 Store 类、install 方法进行抽离,使 index.js 入口仅做方法的聚合并向外导出:
所以,新建 src/vuex/store.js,用于创建并实现 Store 类、install 方法并向外导出:
// src/vuex/store.js
// 容器的初始化
export class Store {
}
// 插件安装逻辑:当Vue.use(Vuex)时执行
export const install =()=>{
}
在 src/vuex/index.js 入口文件中,进行能力聚合并继续向插件外部的应用层导出:
// src/vuex/index.js
import { Store, install } from './store';
export default {
Store,
install
}
这样做的好处是:vuex 插件提供的能力可统一通过此方式对外导出,如:mapState 等方法;
4,install 插件安装逻辑
vuex 与 vue-router 的插件安装逻辑相似;
当执行Vue.use(Vuex)
时,install 方法中会传入 Vue 构造函数,使 vuex 插件依赖项目使用的 Vue 版本:
// src/vuex/store.js
// 导出传入的 Vue 的构造函数,供插件内部的其他文件使用
export let Vue;
/**
* 插件安装逻辑:当Vue.use(Vuex)时执行
* @param {*} _Vue Vue 的构造函数
*/
export const install = (_Vue) => {
Vue = _Vue;
}
同时,在new Vue
初始化(根组件)时,注入的 store 容器实例,混入到所有组件中,为所有组件添加 store 属性:
创建 src/vuex/mixin.js,使用 Vue.mixin 实现全局混入:
// src/vuex/mixin.js
/**
* 将根组件中注入store实例,混入到所有子组件上
* @param {*} Vue
*/
export default function applyMixin(Vue) {
// 通过 beforeCreate 生命周期,在组件创建前,实现全局混入
Vue.mixin({
beforeCreate: vuexInit,// vuexInit 为初始化混入逻辑
});
}
在 src/vuex/store.js 中引入 applyMixin 方法,在 install 方法中调用:
// src/vuex/store.js
import applyMixin from "./mixin";
export const install = (_Vue) => {
Vue = _Vue;
applyMixin(Vue);
}
组件混入(共享)store 实例的原理:
组件的渲染是先渲染父组件再渲染子组件,所以,根组件中注入的 store 实例,就可以被混入到 App.vue 组件上。
同理,逐层地,由父组件向子组件传递 store 实例,实现所有组件共享 store 容器实例;
function vuexInit() {
const options = this.$options;
// 若选项中存在 store 属性,说明是根实例;否则是子实例;
if (options.store) {// 根实例
// 为根实例添加 $store 属性,指向 store 实例
this.$store = options.store;
} else if (options.parent && options.parent.$store) { // 子实例
// 儿子通过父亲拿到 $store 属性,放到自己身上继续提供给儿子
this.$store = options.parent.$store;
}
}
5,测试混入效果
使用新建的 vuex 作为状态管理插件:
// src/store/index.js
import Vue from 'vue';
// import Vuex from 'vuex'; // vuex 官方插件
import Vuex from '@/vuex'; // 自建 Vuex 插件
在 App.vue 中,打印组件上的 $store 属性,查看是否成功混入了来自根组件的 store 实例:
// src/App.vue
<script>
export default {
mounted(){
console.log(this.$store);
}
}
</script>
执行 npm run serve 启动服务:
输出结果:Store {}
打印结果是一个 Store 对象,说明属性混入成功!
三,结尾
本篇,介绍了 vuex 的 install 插件安装逻辑,包含以下几个点:
- 创建 vuex 插件目录;
- Vuex 插件的模块化设计;
- 实现插件安装 install 方法,store 实例混入逻辑;
- 混入效果测试;
下一篇,介绍 Vuex 中 State 状态的实现;
维护日志
- 20210918:
- 调整了部分措辞与代码注释;
- 优化了流程相关的描述;
- 针对 store 实例共享与组件属性混入进行扩充;
- 更新文章摘要;