幾十行程式碼實現一個vue的狀態管理

Jike發表於2019-01-28

介紹

採用集中式儲存管理應用的所有元件的狀態, 就能實現元件間資料共享

實現

邏輯圖

幾十行程式碼實現一個vue的狀態管理

從圖上有兩條線: Vue.use(vuec), 與 new Vuec.center(options)

第一條線Vue.use(vuec)安裝外掛

使用Vue.use(vuec)時, 會執行vuecinstall方法,會注入引數Vue所以vuec是這樣的,

// index.jsimport {Center, install
} from './center'export default {Center, install
}複製程式碼

Center物件將例項化成center(下面再說),我們先看看install方法

// center.jslet Vue // 全域性變數, 儲存install裡的Vueexport function install (_Vue) { 
if (!Vue) {
_Vue.mixin({
beforeCreate: applyMixin // 在beforeCreate鉤子上混入applyMixin函式
})
} Vue = _Vue
}複製程式碼

installVue原型的beforeCreate混入applyMixin函式, 也就是說在生成每個Vue元件時,在它的生命週期beforeCreate鉤子上就會執行applyMixin方法

第二條線 new Vuec.center(options)例項化Center物件

先看看使用者傳入的options, 下面例子

export default new Vuec.Center({ 
state: {
name: 'liuyang'
}, mutations: {
changeName (state) {
state.name = 'jike'
}
}
})複製程式碼

上面程式碼會生成center例項, 該例項上應該包括:state狀態,commit方法提交變更等

// center.jsexport class Center { 
constructor (options= {
}) {
let center = this this.mutations = options.mutations observeState(center, options.state)
} get state () {
// 代理了this.$center.state的最終訪問值 return this._vm.$data.$$state
} commit (_type, _payload) {
this.mutations[_type](this.state, _payload)
}
}function observeState(center, state) {
// 響應式state center._vm = new Vue({
data: {
$$state: state
}
})
}複製程式碼

在執行new Vuec.Center({..
})
時,就是執行Center的建構函式

  1. 首先執行let center = this, 定義center儲存當前例項

  2. 接著執行this.mutations = options.mutations, 在例項center上新增mutations屬性, 值就是使用者輸入mutations,

    按上面例子, this.mutations長成這樣

    this.mutations = { 
    changeName (state) {
    state.name = 'jike'
    }
    }複製程式碼
  3. 最後執行observeState(center, options.state), 作用:讓center例項的state屬性指向options.state並且是響應式的

    function observeState(center, state) { 
// 響應式state center._vm = new Vue({
// 利用Vue的響應系統,將state轉化成響應式 data: {
$$state: state
}
})
}複製程式碼

center例項上新增_vm屬性, 值是一個Vue例項, 在該Vue例項的data下定義了$$state, 它的值是options.state使用者輸入的state;
結合上面的這段程式碼

// center.jsexport class Center { 
...省略 get state () {
// 代理了this.$center.state的最終訪問值 return this._vm.$data.$$state
} ...省略
}複製程式碼

所以我們在元件中訪問center.state其實就是訪問center._vm.$data.$$state

OK, center就構建好了

建立Vue元件

使用者輸入

import Vue from 'vue'import App from './App'import router from './router'import center from './center'new Vue({ 
el: '#app', router, center, // 構建好的center例項 template: '<
App/>
'
, components: {App
}
})複製程式碼

beforeCreate生命週期時會觸發上面混入的applyMixin函式

// mixins.jsexport default function applyMixin() { 
vuecInit.call(this) //
}function vuecInit () {
const options = this.$options // vue的例項化是從外往內, 所以父元件的$center一定是options的center this.$center = options.parent?options.parent.$center: options.center
}複製程式碼

applyMixin裡會執行vuecInit.call(this), 這裡的this指向當前元件的例項,

接著看vuecInit, 定義了options等於使用者輸入選項,因為先建立根元件, 所以根元件this.$center的值的引用就是我們在new Vue({..center
})
時傳入的center例項, 下面所有元件都指向它

OK, 你就可以在元件裡使用this.$center訪問了

commit變更

// center.jsexport class Center { 
... 省略 commit (_type, _payload) {
this.mutations[_type](this.state, _payload)
}
}複製程式碼

通常我們變更時: this.$center.commit('changeName', 'jike'), 這樣的話, this.mutations[_type]就是對應方法函式, 往該函式裡傳入state以及payload,

舉上面的例子

// this.mutations[_type] , _type = 'changeName', payload= 'jike'this.mutations = { 
changeName (state, payload) {
state.name = payload
}
}複製程式碼

說明

上面只是一個簡單的狀態管理, 還有很多地方沒有實現: actions非同步變更,getters函式,modules模組分割, 輔助函式mapState..

原始碼地址: github

來源:https://juejin.im/post/5c4c1f23518825254b5a4e25#comment

相關文章