詳解幾十行代碼實(shí)現(xiàn)一個(gè)vue的狀態(tài)管理
介紹
采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài), 就能實(shí)現(xiàn)組件間數(shù)據(jù)共享
實(shí)現(xiàn)
邏輯圖
從圖上有兩條線: Vue.use(vuec), 與 new Vuec.center(options)
第一條線Vue.use(vuec)安裝插件
使用Vue.use(vuec)時(shí), 會(huì)執(zhí)行vuec的install方法,會(huì)注入?yún)?shù)Vue 所以vuec是這樣的,
// index.js import {Center, install} from './center' export default {Center, install}
Center對(duì)象將實(shí)例化成center(下面再說),我們先看看install方法
// center.js let Vue // 全局變量, 保存install里的Vue export function install (_Vue) { if (!Vue) { _Vue.mixin({ beforeCreate: applyMixin // 在beforeCreate鉤子上混入applyMixin函數(shù) }) } Vue = _Vue }
install在Vue原型的beforeCreate混入applyMixin函數(shù), 也就是說在生成每個(gè)Vue組件時(shí),在它的生命周期beforeCreate鉤子上就會(huì)執(zhí)行applyMixin方法
第二條線 new Vuec.center(options)實(shí)例化Center對(duì)象
先看看用戶傳入的options, 下面例子
export default new Vuec.Center({ state: { name: 'liuyang' }, mutations: { changeName (state) { state.name = 'jike' } } })
上面代碼會(huì)生成center實(shí)例, 該實(shí)例上應(yīng)該包括:state狀態(tài),commit方法提交變更等
// center.js export 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) { // 響應(yīng)式state center._vm = new Vue({ data: { $$state: state } }) }
在執(zhí)行new Vuec.Center({..})時(shí),就是執(zhí)行Center的構(gòu)造函數(shù)
首先執(zhí)行l(wèi)et center = this, 定義center保存當(dāng)前實(shí)例
接著執(zhí)行this.mutations = options.mutations, 在實(shí)例center上添加mutations屬性, 值就是用戶輸入mutations,
按上面例子, this.mutations長成這樣
this.mutations = { changeName (state) { state.name = 'jike' } }
最后執(zhí)行observeState(center, options.state), 作用:讓center實(shí)例的state屬性指向options.state并且是響應(yīng)式的
function observeState(center, state) { // 響應(yīng)式state center._vm = new Vue({ // 利用Vue的響應(yīng)系統(tǒng),將state轉(zhuǎn)化成響應(yīng)式 data: { $$state: state } }) }
在center實(shí)例上添加_vm屬性, 值是一個(gè)Vue實(shí)例, 在該Vue實(shí)例的data下定義了$$state, 它的值是options.state用戶輸入的state; 結(jié)合上面的這段代碼
// center.js export class Center { ...省略 get state () { // 代理了this.$center.state的最終訪問值 return this._vm.$data.$$state } ...省略 }
所以我們?cè)诮M件中訪問center.state其實(shí)就是訪問center._vm.$data.$$state
OK, center就構(gòu)建好了
創(chuàng)建Vue組件
用戶輸入
import Vue from 'vue' import App from './App' import router from './router' import center from './center' new Vue({ el: '#app', router, center, // 構(gòu)建好的center實(shí)例 template: '<App/>', components: {App} })
在beforeCreate生命周期時(shí)會(huì)觸發(fā)上面混入的applyMixin函數(shù)
// mixins.js export default function applyMixin() { vuecInit.call(this) // } function vuecInit () { const options = this.$options // vue的實(shí)例化是從外往內(nèi), 所以父組件的$center一定是options的center this.$center = options.parent?options.parent.$center: options.center }
applyMixin里會(huì)執(zhí)行vuecInit.call(this), 這里的this指向當(dāng)前組件的實(shí)例,
接著看vuecInit, 定義了options等于用戶輸入選項(xiàng),因?yàn)橄葎?chuàng)建根組件, 所以根組件this.$center的值的引用就是我們?cè)趎ew Vue({..center})時(shí)傳入的center實(shí)例, 下面所有組件都指向它
OK, 你就可以在組件里使用this.$center訪問了
commit變更
// center.js export class Center { ... 省略 commit (_type, _payload) { this.mutations[_type](this.state, _payload) } }
通常我們變更時(shí): this.$center.commit('changeName', 'jike'), 這樣的話, this.mutations[_type]就是對(duì)應(yīng)方法函數(shù), 往該函數(shù)里傳入state以及payload,
舉上面的例子
// this.mutations[_type] , _type = 'changeName', payload= 'jike' this.mutations = { changeName (state, payload) { state.name = payload } }
說明
上面只是一個(gè)簡單的狀態(tài)管理, 還有很多地方?jīng)]有實(shí)現(xiàn): actions異步變更,getters函數(shù),modules模塊分割, 輔助函數(shù)mapState..等
源碼地址: github
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue使用babel-polyfill兼容IE解決白屏及語法報(bào)錯(cuò)問題
這篇文章主要介紹了Vue使用babel-polyfill兼容IE解決白屏及語法報(bào)錯(cuò)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03vue draggable resizable 實(shí)現(xiàn)可拖拽縮放的組件功能
這篇文章主要介紹了vue draggable resizable 實(shí)現(xiàn)可拖拽縮放的組件功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07vue.js中toast用法及使用toast彈框的實(shí)例代碼
這篇文章主要介紹了vue.js中toast用法及使用toast彈框的實(shí)例代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒加載,需要的朋友可以參考下2018-08-08vue前端實(shí)現(xiàn)導(dǎo)出頁面為pdf(分頁導(dǎo)出、不分頁導(dǎo)出及分模塊導(dǎo)出)
在實(shí)際應(yīng)用中可能用戶希望將系統(tǒng)中一個(gè)頁面展示的所有數(shù)據(jù)報(bào)表,用PDF的文件格式下載下來,以便于其他用途,這篇文章主要給大家介紹了關(guān)于vue前端實(shí)現(xiàn)導(dǎo)出頁面為pdf(分頁導(dǎo)出、不分頁導(dǎo)出及分模塊導(dǎo)出)的相關(guān)資料,需要的朋友可以參考下2024-06-06vue監(jiān)聽瀏覽器網(wǎng)頁關(guān)閉和網(wǎng)頁刷新事件代碼示例
在前端開發(fā)中我們通常會(huì)遇到這樣的需求,用戶離開、刷新頁面前,修改數(shù)據(jù)未進(jìn)行保存操作,需要提示框提醒用戶,這篇文章主要給大家介紹了關(guān)于vue監(jiān)聽瀏覽器網(wǎng)頁關(guān)閉和網(wǎng)頁刷新事件的相關(guān)資料,需要的朋友可以參考下2023-08-08vue利用指令實(shí)現(xiàn)快速設(shè)置元素的高度
在項(xiàng)目中經(jīng)常有需要將列表的高度設(shè)置成剩余可視區(qū)域的高度,本文主要來和大家介紹一下如何通過指令和css變量的方式快速設(shè)置列表高度,希望對(duì)大家有所幫助2024-03-03Vue.js中該如何自己維護(hù)路由跳轉(zhuǎn)記錄
這篇文章主要給大家介紹了關(guān)于Vue.js中該如何自己維護(hù)路由跳轉(zhuǎn)記錄的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue.js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05