简易vuex源码实现

kvuex.js  文件    (实现vuex插件)

// 1、维护状态state
// 2、修改状态commit
// 3、业务逻辑控制dispatch
// 4、状态派发getter
// 5、实现state响应式
// 6、插件
// 7、混入

let Vue

function install(_Vue, storeName = '$store') {
    Vue = _Vue

    // 混入:把store选项指定到Vue原型上
    Vue.mixin({
        beforeCreate() {
            // 判断main.js的当期组件选择中,是否有sotre   
            if(this.$options.store){
                Vue.prototype[storeName] = this.$options.store 
            }
        }
    })
}

class Store {
    // options: { state: {count:0}, mutations:{count(state){}} }
    constructor(options = {}){
        // 利用vue数据响应式
        this.state = new Vue({
            data: options.state
        })

        // 初始化mutations
        this.mutations = options.mutations || {}
        this.actions = options.actions || {}
        options.getters && this.handleGetters(options.getters)
    }

    // 触发mutations,需要实现commit
    commit = (type, arg) => {
        // this只想Store实例
        const fn = this.mutations[type] // 获取状态变更函数
        fn(this.state, arg)
    } 

    dispatch = (type, arg) => {
        const fn = this.actions[type]
        return fn({commit: this.commit, state: this.state}, arg)
    }

    // {getters: {score(state){return state.xx}}}
    handleGetters(getters){
        this.getters = {} // store实例上的getters

        // 定义只读的属性
        Object.keys(getters).forEach(key => {
            Object.defineProperty(this.getters, key, {
                get: () => {
                    return getters[key](this.state)
                }
            })
        })
    }
}

export default {Store, install}

 

kindex.js  文件  相当于store.js文件

import Vue from 'vue'
import KVuex from '../kvuex'

Vue.use(KVuex)

export default new KVuex.Store({
    state: {
        count: 0
    },
    mutations: {
        add(state, num = 1) {
            state.count += num
        }
    },
    getters: { // 相当于计算属性
        score(state) {
            return 'score:' + state.count
        }
    },
    actions: {
        // 处理复杂业务逻辑,类似于controller
        // 比如ajax请求

        asyncAdd({ commit }) { // 参数解构,拿到上下文
            setTimeout(() => {
                commit('add')
            }, 1000);
        }

    }
})

 

测试文件---vue文件

<template>
    <div>
        <h3>vuex test</h3>
        <p>{{$store.state.count}}</p>
        <p>{{$store.getters.score}}</p>
        <button @click="add">add</button>
        <button @click="asyncAdd">asyncAdd</button>
    </div>
</template>

<script>
export default {
    methods: {
        add() {
            this.$store.commit('add', 2)
        },
        asyncAdd(){
            this.$store.dispatch('asyncAdd')
        }
    },
}
</script>

 

posted @ 2019-08-07 15:38  落叶无痕~  阅读(448)  评论(0编辑  收藏