vue create projectName
进入项目
cd projectName
安装vuex
vue add vuex
在store/index.js中写上测试代码:
import Vue from "vue";
import Vuex from "./jvuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
state.count++;
}
},
actions: {
add({ commit }) {
setTimeout(() => {
commit("add");
}, 1000);
}
},
modules: {}
});
App.vue中写测试代码:
{
{$store.state.count}}
async: {
{$store.state.count}}
手写vuex:在store文件夹中创建jvuex.js文件。
将index.js文件中引入Vuex地址改为jvuex.js的地址
import Vuex from "vuex";
import Vuex from "./jvuex";
1.由于组件中使用Vuex时,是new Vuex.Store(...),所以我们应该暴露出一个包含Store和install的对象。
为了在组件中能直接用this.$store,所以要将store挂载到vue原型链上。犹豫install方法是在创建vue实例之前执行,所以使用混合的方式,将挂载延迟到beforeCreate时
let Vue;
class Store {
constructor() {}
}
function install(_vue) {
Vue = _vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
}
});
}
export default {Store, install}
2.分析state:state中数据改变时,相应的位置也会重新渲染,所以state中的数据应设置为响应式数据,可以创建vue实例,将state传进去,但不能让用户随意操作state,所以要尽量把state隐藏起来。在get的时候返回对应的值,在set时进行报错处理。
let Vue;
class Store {
constructor(options) {
// 将state中的数据做响应式处理
// 为了不暴露vue实例,用_vm隐藏
// 添加$$,Vue就不会代理,_vm就访问不到options.state中的属性,将options.state尽可能隐藏起来,用户只能使用state的方式访问options.state
this._vm = new Vue({
data: {
$$state: options.state
}
});
}
get state() {
return this._vm._data.$$state;
}
set state(v) {
console.error("请使用replaceState重置状态");
}
}
function install(_vue) {
Vue = _vue
}
export default {Store, install}
3.commit:使用时传入mutation类型和数据两个参数,执行该类型的方法
constructor(options) {
this._mutations = options.mutations;
}
commit(type, payload) {
const mutation = this._mutations[type];
if (mutation) {
mutation(this.state, payload);
}
}
4.dispatch:使用时传入action类型和数据两个参数,执行该类型的方法
constructor(options) {
this._actions= options.actions;
}
dispatch(type, payload) {
const action = this._actions[type];
if (action) {
// 执行的类型方法第一个参数是上下文
action(this, payload);
}
}
5.getters:getters需要借助computed来实现,遍历getters中的属性,在computed中设置一样的属性,由于computed中的属性会挂载到vue原型链上,且是响应式的,所以当获取getters中属性时,可以使用在vue实例上获取到
// 初始化computed,方便getters中使用
const computed = {};
this._wrappedGetters = options.getters;
this.getters = {};
// 由于forEach中的this已经不再是Store实例,所以在这里将this存为store
const store = this;
// 遍历getters中的属性
Object.keys(this._wrappedGetters).forEach(key => {
// 获取getters
const fn = store._wrappedGetters[key];
// 由于使用computed时不能带参数,所以我们在computed中设置同名参数,返回高阶函数fn,并传入参数执行
computed[key] = function() {
return fn(store.state)
}
// 由于用户只能读取getters,所以只定义只读属性
Object.defineProperty(store.getters, key, {
// computed中把key都放到_vm中了,所以这里可以用_vm获取key
get: () => store._vm[key]
})
})
// 将state中的数据做响应式处理
// 为了不暴露vue实例,用_vm隐藏
// 添加$$,Vue就不会代理,_vm就访问不到options.state中的属性,将options.state尽可能隐藏起来,用户只能使用state的方式访问options.state
this._vm = new Vue({
data: {
$$state: options.state
},
// 设置computed
computed:computed
});
let Vue;
class Store {
constructor(options) {
this._mutations = options.mutations;
this._actions = options.actions;
// 在使用时不知道上下文是谁了,所以这里锁死Store实例
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
// 初始化computed,方便getters中使用
const computed = {};
this._wrappedGetters = options.getters;
this.getters = {};
// 由于forEach中的this已经不再是Store实例,所以在这里将this存为store
const store = this;
Object.keys(this._wrappedGetters).forEach(key => {
// 获取getters
const fn = store._wrappedGetters[key];
// 由于使用computed时不能带参数,所以我们在computed中设置同名参数,返回高阶函数fn,并传入参数执行
computed[key] = function() {
return fn(store.state)
}
// 由于用户只能读取getters,所以只定义只读属性
Object.defineProperty(store.getters, key, {
// computed中把key都放到_vm中了,所以这里可以用_vm获取key
get: () => store._vm[key]
})
})
// 将state中的数据做响应式处理
// 为了不暴露vue实例,用_vm隐藏
// 添加$$,Vue就不会代理,_vm就访问不到options.state中的属性,将options.state尽可能隐藏起来,用户只能使用state的方式访问options.state
this._vm = new Vue({
data: {
$$state: options.state
},
// 设置computed
computed:computed
});
}
get state() {
return this._vm._data.$$state;
}
set state(v) {
console.error("请使用replaceState重置状态");
}
commit(type, payload) {
const mutation = this._mutations[type];
if (mutation) {
mutation(this.state, payload);
}
}
dispatch(type, payload) {
const action = this._actions[type];
if (action) {
action(this, payload);
}
}
}
function install(_vue) {
Vue = _vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
}
});
}
export default { Store, install };