手写vuex简版
template
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p @click="$store.commit('add')">counter: {{$store.state.counter}}</p>
<p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
<p>{{$store.getters.doubleCounter}}</p>
</div>
</template>
store/index.js
import Vue from "vue";
import Vuex from "./zhen-vuex";
// this.$store
// this.$store.state.xxx
Vue.use(Vuex);
export default new Vuex.Store({
state: {
counter: 0,
},
mutations: {
add(state) {
// state从哪来?
state.counter++;
},
},
actions: {
add({ commit }) {
// 参数是什么,哪来的?
setTimeout(() => {
commit("add");
}, 1000);
},
},
getters: {
doubleCounter(state) {
return state.counter * 2;
},
},
});
zhen-vuex手写
//实现目标
// 1.插件:挂载$store
// 2.实现Store
let Vue; //首先保存Vue构造函数
class Store {
// 把vuex.state都变成响应式.用defineReavtive只能定义.借助new Vue能对vuex.state全部进行响应式处理
constructor(opotions) {
this._mutations = opotions.mutations;
this._actions = opotions.actions;
this._wrappedGetters = opotions.getters;
// 定义computed选项
const computed = {};
this.getters = {};
const store = this; //保存this指向
// opotions.getters => {doubleCouter(state){}}
Object.keys(this._wrappedGetters).forEach((key) => {
// 获取用户定义的getter
const fn = store._wrappedGetters[key];
// 转换为computed可以使用的无参数的形式
computed[key] = function() {
return fn(store.state);
};
// 为getters定义只读属性(用户只能访问getters)
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
});
});
// this.state = new Vue({
// data: opotions.state,
// });
// 对上面改写成不对外暴露的形式
// $$state是访问不到的,会被隐藏起来
this._vm = new Vue({
data: {
$$state: opotions.state,
},
computed,
});
// 绑定commit、dispatch的上下文store实例
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
// 对this.state进行隐藏,并不想外界去修改它,通过get的方式
get state() {
// _data和$data两者是一样的,
return this._vm._data.$$state;
}
set state(v) {
console.error("不能对vuex中的state进行直接修改");
}
commit(type, payload) {
const entry = this._mutations[type];
if (!entry) {
console.error("未知mutations类型");
}
entry(this.state, payload);
}
dispatch(type, payload) {
const entry = this._actions[type];
if (!entry) {
console.error("未知actions类型");
}
entry(this, payload);
}
}
function install(_Vue) {
Vue = _Vue;
// Vue.use(install)的执行时间在很靠前的,这个时候还获取不到Vuex实例中,所以要巧妙的运用到Vue.mixin的beforeCreate()方法获取并挂载Vuex
// 全局混入(每个组件都会用到)
// 全局混入目的:延迟下面逻辑到vuex已经创建完毕并且附加到选项上时才执行
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
},
});
}
// 为什么要{ store, install } Vue.use(Vuex);use的是Vuex.install//export default new Vuex.Store
export default { Store, install };

浙公网安备 33010602011771号