1. 程式人生 > 程式設計 >實現vuex原理的示例

實現vuex原理的示例

效果圖如下:

實現vuex原理的示例

1. 準備好環境

使用 vue/cil 初始化專案配置:

npm install -g @vue/cli //全域性安裝@vue/cli vue create demo-vue //建立專案

yarn add vuex安裝vuex建立一個store資料夾並使用:

實現vuex原理的示例

2. 實現目的

stroe/index.js內容如下:(我們的目的將引入自寫的vuex實現vuex基礎功能)

import Vue from 'vue'
import Vuex from 'vuex' 
// import Vuex from './myvuex'   //我們實現的 青銅版vuex
// import Vuex from './myvuexplus' //我們實現的 白銀版vuex

Vue.use(Vuex) //執行install方法 將new Vuex.Store掛載到this.$store

export default new Vuex.Store({
 state: {
  counter: 0,userData: {
   name: '時間',age: 18
  }
 },getters: {
  name(state) {
   return state.userData.name
  }
 },mutations: {
  add(state) {
   state.counter++
  },updateName(state,payload) {
   state.userData.name = payload
  }
 },actions: {
  add({ commit }) {
   setTimeout(() => {
    commit('add')
   },1000);
  }
 }
})

  • 青銅版vuexmyvuex.js程式碼如下:
let Vue
class Store {
 constructor(options) {
  this._vm = new Vue({
   data: {
    state: options.state
   }
  })

  let getters = options.getters
  this.getters = {}
  Object.keys(getters).forEach((val) => {
   Object.defineProperty(this.getters,val,{ //getters響應式
    get: () => {
     return getters[val](this.state)
    }
   })
  })

  this._actions = Object.assign({},options.actions)
  this._mutations = Object.assign({},options.mutations)
 }

 // get/set state目的:防止外部直接修改state
 get state() {
  return this._vm.state
 }
 set state(value) {
  console.error('please use replaceState to reset state')
 }

 commit = (funName,params) => { //this執行問題
  // 在mutations中找到funName中對應的函式並且執行
  this._mutations[funName](this.state,params)
 }

 dispatch(funName,params) {
  this._actions[funName](this,params)
 }
}

function install(vue) {
 Vue = vue
 vue.mixin({
  beforeCreate () {
   // 將 new Store() 例項掛載到唯一的根元件 this 上
   if (this.$options?.store) {
    this.$store = this.$options.store
   } else {
    this.$store = this.$parent && this.$parent.$store
   }
  }
 })
}

export default {
 Store,install
}

青銅版vuex this.$stroe:

實現vuex原理的示例

  • 白銀版vuexmyvuexplus.js程式碼如下:
let _Vue
const install = function(Vue,opts) {
 _Vue = Vue
 _Vue.mixin({ // 因為我們每個元件都有 this.$store這個東西,所以我們使用混入模式
  beforeCreate () { // 從根元件向子元件遍歷賦值,這邊的 this 就是每個 Vue 例項
   if (this.$options && this.$options.store) { // 這是根節點
    this.$store = this.$options.store
   } else {
    this.$store = this.$parent && this.$parent.$store
   }
  }
 })
}

class ModuleCollection {
 constructor(opts) {
  this.root = this.register(opts)
 }

 register(module) {
  let newModule = {
   _raw: module,_state: module.state || {},_children: {}
  }
  Object.keys(module.modules || {}).forEach(moduleName => {
   newModule._children[moduleName] = this.register(module.modules[moduleName])
  })
  return newModule
 }
}

class Store {
 constructor(opts) {
  this.vm = new _Vue({
   data () {
    return {
     state: opts.state // 把物件變成響應式的,這樣才能更新檢視
    }
   }
  })

  this.getters = {}
  this.mutations = {}
  this.actions = {}

  // 先格式化傳進來的 modules 資料
  // 巢狀模組的 mutation 和 getters 都需要放到 this 中
  this.modules = new ModuleCollection(opts)
  console.log(this.modules)

  Store.installModules(this,[],this.modules.root)
 }

 commit = (mutationName,value) => { // 這個地方 this 指向會有問題,這其實是掛載在例項上
  this.mutations[mutationName].forEach(f => f(value))
 }

 dispatch(actionName,value) {
  this.actions[actionName].forEach(f => f(value))
 }

 get state() {
  return this.vm.state
 }
}
Store.installModules = function(store,path,curModule) {
 let getters = curModule._raw.getters || {}
 let mutations = curModule._raw.mutations || {}
 let actions = curModule._raw.actions || {}
 let state = curModule._state || {}

 // 把子模組的狀態掛載到父模組上,其他直接掛載到根 store 上即可
 if (path.length) {
  let parent = path.slice(0,-1).reduce((pre,cur) => {
   return pre[cur]
  },store.state)
  _Vue.set(parent,path[path.length - 1],state)
 }

 Object.keys(getters).forEach(getterName => {
  Object.defineProperty(store.getters,getterName,{
   get: () => {
    return getters[getterName](state)
   }
  })
 })

 Object.keys(mutations).forEach(mutationName => {
  if (!(store.mutations && store.mutations[mutationName])) store.mutations[mutationName] = []
  store.mutations[mutationName].push(value => {
   mutations[mutationName].call(store,state,value)
  })
 })

 Object.keys(actions).forEach(actionName => {
  if (!(store.actions && store.actions[actionName])) store.actions[actionName] = []
  store.actions[actionName].push(value => {
   actions[actionName].call(store,store,value)
  })
 })

 Object.keys(curModule._children || {}).forEach(module => {
  Store.installModules(store,path.concat(module),curModule._children[module])
 })


}

// computed: mapState(['name'])
// 相當於 name(){ return this.$store.state.name }
const mapState = list => { // 因為最後要在 computed 中呼叫
 let obj = {}
 list.forEach(stateName => {
  obj[stateName] = () => this.$store.state[stateName]
 })
 return obj
}

const mapGetters = list => { // 因為最後要在 computed 中呼叫
 let obj = {}
 list.forEach(getterName => {
  obj[getterName] = () => this.$store.getters[getterName]
 })
 return obj
}

const mapMutations = list => {
 let obj = {}
 list.forEach(mutationName => {
  obj[mutationName] = (value) => {
   this.$store.commit(mutationName,value)
  }
 })
 return obj
}

const mapActions = list => {
 let obj = {}
 list.forEach(actionName => {
  obj[actionName] = (value) => {
   this.$store.dispatch(actionName,value)
  }
 })
 return obj
}

export default {
 install,Store,mapState,mapGetters,mapMutations,mapActions
}

白銀版vuex this.$stroe:

實現vuex原理的示例

3. App.vue 內使用自寫的vuex:

<template>
 <div id="app">
  <button @click="$store.commit('add')">$store.commit('add'): {{$store.state.counter}}</button>
  <br>
  <button @click="$store.commit('updateName',new Date().toLocaleString())">$store.commit('updateName',Date): {{$store.getters.name}}</button>
  <br>
  <button @click="$store.dispatch('add')">async $store.dispatch('add'): {{$store.state.counter}}</button>
 </div>
</template>
<script>
...

以上就是實現vuex原理的示例的詳細內容,更多關於實現vuex原理的資料請關注我們其它相關文章!