vuex如何实现

124 阅读1分钟

vuex的用法

完整vuex内传入对象 一般需要 state、mutation、actions

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)  // 插件引用

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state) {
      // state从哪来
      state.count++
    }
  },
  actions: {
    // 上下文对象是什么,从哪来
    add({commit}) {
      setTimeout(() => {
        commit('add')
      }, 1000);
    }
  },
  modules: {
  }
})

实现注意点:

1、mutation的方法实现传入需要state

2、action 传入需要 { commit }

3、action 使用时需要dispatch触发

在页面上的使用

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <router-link to="/404">404</router-link>
    </div>

    <div>
      data:
      {{$store.state}}
    </div>
    <div>
      全局状态:
      <p @click="$store.commit('add')">{{$store.state.count}}</p>
    </div>
    <div>
      <p @click="$store.dispatch('add')">{{$store.state.count}}</p>
    </div>
    <p>{{$store.getters.doubleCounter}}</p>
    <p>{{$store.cpGetters.doubleCounter}}</p>
    <router-view />
  </div>
</template>

使用分析:

1、$store 在 beforeCreate 的时候把 store 挂上 this

2、$store.commit 执行 mutation 的操作

3、$store.dispatch 执行 action 上的操作

4、$store.getters 类似 computed 的操作


具体实现

实现store类的架构预演

步骤:

  1. 维持一个响应式状态state
  2. 实现commit
  3. 实现dispatch
  4. getters
  5. 挂载store

1、实现store

let Vue  // 通过install传入

class Store {
  // 构造器
  constructor({ state, mutations, actions, getters }) {
    // 很明显要给state内的值作响应式
    // 这样才能做视图更新
  }
  
  // commit  传入 mutation定义的方法key值、以及进行处理的值
  
  commit(type, payload) {}
  
  // dispatch 传入 action定义的方法key值、以及进行处理的值
  
  dispatch(type, payload)  {}
  
}

// 处理 install 可以让Vue.install 方法

function install(_vue) {
	Vue = _vue
	// 延迟挂载store
	Vue.mixin({
		beforeCreate() {
			if (this.$options.store) {
				Vue.prototype.$store = this.$options.store
			}
		}
	})
}

export default {
	Store,
	install
}


// 这里导出对象区别于 router 
// 因为平常使用 vuex的时候 是 new Vuex.Store({})

// 而router的使用是直接 new Router({}) 

2、具体实现

class Store {
	constructor({ state, mutations, actions, getters }) {
		
		// 1.保存选项
		this._state = state
		this._mutations = mutations || {}
		this._actions = actions || {}
		// 内部方法绑定this
		this.commit = this.commit.bind(this)
		this.dispatch = this.dispatch.bind(this)

		const computed = {}
		for (let key in getters) {
			const fn = getters[key]
			computed[key] = () => {
                return fn(this.state)
            }
		}
		
		// 2.做响应式state属性
		this._vm = new Vue({
			data: function() {
				return { $$state: state }
            },
            computed
		})
		
		// 3.getters
		// 动态设置getters属性  还有 响应式
		// 附加能否利用上vue的compute属性
		console.log('getters实现')
		const _getters = {}
		
		for (let key in getters) {
			const innerState = this.state // 内部获取不到this
			// const item = getters[key]
			Object.defineProperty(_getters, key, {
				get: function() {
					return getters[key](innerState)
				},
				enumerable: true
			})
		}
		this.getters = _getters
	}

	get state() { // 利用data实现, return _vm.$$state 也可
		//_data 响应对象 $data原始对象
		return this._vm._data.$$state
	}

	set state(v) {
		console.log("error can't set val")
	}
  
    get cpGetters() { // 利用vue computed实现
        return this._vm
    }

	commit(type, payload) {
		// 获取mutations
		const entry = this._mutations[type]
		if (!entry) {
			console.log('获取不到mutations')
			return
		}
		entry(this.state, payload)
	}

	dispatch(type, payload) {
		const entry = this._actions[type]
		if (!entry) {
			console.log('获取不到actions')
			return
		}
		// commit 和 dispatch 绑过this 所以可以使用
		entry(this, payload)
	}
}