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 };