摘要:從開始學(xué)習(xí)源碼前言嘗試從開始,寫一個(gè)主要是的源代碼,從中學(xué)習(xí)下的源代碼先來(lái)看下列子中是怎么使用的。開始第一步作為一個(gè)插件先得實(shí)現(xiàn)方法。先定義一個(gè)變量。一是為了注入到各個(gè)組件,二是后續(xù)要用到的雙向綁定的功能依賴雙向綁定構(gòu)造下。
Vuex從0開始學(xué)習(xí)源碼 前言
嘗試從0開始,寫一個(gè)Vuex(主要是copy vuex的源代碼),從中學(xué)習(xí)下vuex的源代碼.先來(lái)看下列子中是怎么使用store的。
import Vue from "vue" import Vuex from "../../src" Vue.use(Vuex) // mutation types // optional if you don"t like constants. const INCREMENT = "INCREMENT" const DECREMENT = "DECREMENT" // root state object. // each Vuex instance is just a single state tree. const state = { count: 0 } // actions are what components will be able to // call as store.actions.xxx // note these are not the final functions the // components will be calling. const actions = { // for simple actions that just dispatches a single mutation, // we can just provide the mutation type. increment: INCREMENT, decrement: DECREMENT, // for a normal action function, it always recieves the store // instance as the first argument, from which we can get the // dispatch function and the state object. Any additional // arguments will follow the store argument. incrementIfOdd: ({ dispatch, state }) => { if ((state.count + 1) % 2 === 0) { dispatch(INCREMENT) } }, // Same thing for async actions. incrementAsync: ({ dispatch }) => { setTimeout(() => { dispatch(INCREMENT) }, 1000) } } // mutations are operations that actually mutates the state. // each mutation handler gets the entire state tree as the // first argument, followed by additional payload arguments. // mutations must be synchronous and can be recorded by middlewares // for debugging purposes. const mutations = { [INCREMENT] (state) { state.count++ }, [DECREMENT] (state) { state.count-- } } // A Vuex instance is created by combining the state, the actions, // and the mutations. Because the actions and mutations are just // functions that do not depend on the instance itself, they can // be easily tested or even hot-reloaded (see counter-hot example). // // You can also provide middlewares, which is just an array of // objects containing some hooks to be called at initialization // and after each mutation. export default new Vuex.Store({ state, actions, mutations })開始 第一步
Vuex作為一個(gè)插件 先得實(shí)現(xiàn)install方法。同時(shí)我們?cè)趇nstall方法里面在Vue組件注入$store,也就是為什么vue中各個(gè)子組件為什么能夠通過(guò)this.$store訪問(wèn)到store這個(gè)對(duì)象
let Vue //存儲(chǔ)Vue變量。一是為了注入$store到各個(gè)Vue組件,二是后續(xù)要用到Vue的雙向綁定的功能 export class Store{ } export function install (_Vue){ Vue = _Vue const _init = Vue.prototype._init; Vue.prototype._init = function(options){ options = options || {} if(options.store){ this.$store = options.store }else if(options.parent && options.parent.$store){ this.$store = options.parent.$store } _init.call(this,options) } } export default { Store,install }
上述代碼中。
先定義一個(gè)Vue變量。有兩個(gè)作用
第一個(gè)作用就是給Vue各個(gè)組件注入$store變量,另外一個(gè)功能后面會(huì)說(shuō)到
我們使用vuex的時(shí)候,會(huì)傳入state給頁(yè)面訪問(wèn),同時(shí)支持當(dāng)頁(yè)面中用到state里面的變量的時(shí)候。及時(shí)更新?tīng)顟B(tài)。這里就會(huì)Vue的另外一個(gè)功能,雙向綁定。
let Vue //存儲(chǔ)Vue變量。一是為了注入$store到各個(gè)Vue組件,二是后續(xù)要用到Vue的雙向綁定的功能 export class Store{ constructor ({ state = {}, actions = {}, mutations = {} }){ //依賴vue雙向綁定 this._vm = new Vue({ data : state }) } get state (){ //頁(yè)面中通過(guò)此方法獲取state return this._vm._data; } set state (v){ throw new Error("[Vuex] vuex root state is read only.") } } export function install (_Vue){ Vue = _Vue const _init = Vue.prototype._init; Vue.prototype._init = function(options){ options = options || {} if(options.store){ this.$store = options.store }else if(options.parent && options.parent.$store){ this.$store = options.parent.$store } _init.call(this,options) } } export default { Store,install }
可以看到頁(yè)面中count的數(shù)值已經(jīng)可以顯示了
Vuex中的action是用來(lái)干嘛?是用來(lái)dispatch事件,從而來(lái)執(zhí)行mutations的,中間可以穿插一些邏輯,所以我們封裝下actions
import { createAction, mergeObjects } from "./util" let Vue //存儲(chǔ)Vue變量。一是為了注入$store到各個(gè)Vue組件,二是后續(xù)要用到Vue的雙向綁定的功能 export class Store{ constructor ({ state = {}, actions = {}, mutations = {} }){ //依賴vue雙向綁定 this._vm = new Vue({ data : state }) this.actions = Object.create(null) //構(gòu)造下action。兼容字符串和function兩種模式 this._setupActions(actions); } get state (){ //頁(yè)面中通過(guò)此方法獲取state return this._vm._data; } set state (v){ throw new Error("[Vuex] vuex root state is read only.") } _setupActions (actions){ this._actions = Object.create(null); actions = Array.isArray(actions) ? mergeObjects(actions) : actions; Object.keys(actions).forEach(name =>{ this._actions[name] = createAction(actions[name],this); //兼容string 和function的寫法 if(!this.actions[name]){ this.actions[name] = (...args) =>this._actions[name](...args) } }) } } export function install (_Vue){ Vue = _Vue const _init = Vue.prototype._init; Vue.prototype._init = function(options){ options = options || {} if(options.store){ this.$store = options.store }else if(options.parent && options.parent.$store){ this.$store = options.parent.$store } _init.call(this,options) } } export default { Store,install }
utils.js中的代碼
export function createAction (action, store) { if (typeof action === "string") { // simple action string shorthand return (...payload) => store.dispatch(action, ...payload) } else if (typeof action === "function") { // normal action return (...payload) => action(store, ...payload) } }第四步 構(gòu)造下mutations
這步比較簡(jiǎn)單,直接看代碼
import { createAction, mergeObjects } from "./util" let Vue //存儲(chǔ)Vue變量。一是為了注入$store到各個(gè)Vue組件,二是后續(xù)要用到Vue的雙向綁定的功能 export class Store{ constructor ({ state = {}, actions = {}, mutations = {} }){ //依賴vue雙向綁定 this._vm = new Vue({ data : state }) this.actions = Object.create(null) //構(gòu)造下action。兼容字符串和function兩種模式 this._setupActions(actions); //構(gòu)造mutations this._setupMutations(mutations); } get state (){ //頁(yè)面中通過(guò)此方法獲取state return this._vm._data; } set state (v){ throw new Error("[Vuex] vuex root state is read only.") } _setupActions (actions){ this._actions = Object.create(null); actions = Array.isArray(actions) ? mergeObjects(actions) : actions; Object.keys(actions).forEach(name =>{ this._actions[name] = createAction(actions[name],this); //兼容string 和function的寫法 if(!this.actions[name]){ this.actions[name] = (...args) =>this._actions[name](...args) } }) } _setupMutations(mutations){ this._mutations = Array.isArray(mutations) ? mergeObjects(mutations,true) : mutations } } export function install (_Vue){ Vue = _Vue const _init = Vue.prototype._init; Vue.prototype._init = function(options){ options = options || {} if(options.store){ this.$store = options.store }else if(options.parent && options.parent.$store){ this.$store = options.parent.$store } _init.call(this,options) } } export default { Store,install }第五步,實(shí)現(xiàn)dispatch方法
我們知道我們?cè)赼ction里面dispatch事件了。這個(gè)就類似現(xiàn)在的commit。dispatch事件,是要執(zhí)行mutations的
import { createAction, mergeObjects } from "./util" let Vue //存儲(chǔ)Vue變量。一是為了注入$store到各個(gè)Vue組件,二是后續(xù)要用到Vue的雙向綁定的功能 export class Store{ constructor ({ state = {}, actions = {}, mutations = {} }){ //依賴vue雙向綁定 this._vm = new Vue({ data : state }) this.actions = Object.create(null) //構(gòu)造下action。兼容字符串和function兩種模式 this._setupActions(actions); //構(gòu)造mutations this._setupMutations(mutations); } get state (){ //頁(yè)面中通過(guò)此方法獲取state return this._vm._data; } set state (v){ throw new Error("[Vuex] vuex root state is read only.") } _setupActions (actions){ this._actions = Object.create(null); actions = Array.isArray(actions) ? mergeObjects(actions) : actions; Object.keys(actions).forEach(name =>{ this._actions[name] = createAction(actions[name],this); //兼容string 和function的寫法 if(!this.actions[name]){ this.actions[name] = (...args) =>this._actions[name](...args) } }) } _setupMutations(mutations){ this._mutations = Array.isArray(mutations) ? mergeObjects(mutations,true) : mutations } /** * 執(zhí)行mutation */ dispatch (type,...payload) { const mutation = this._mutations[type]; const state = this.state; if(mutation){ this._dispatching = true if(Array.isArray(mutation)){ //遍歷執(zhí)行 mutation.forEach(m =>m(state,...payload)) }else{ mutation(state,...payload) } this._dispatching = false }else{ console.warn("[vuex] unknown mutation:${type}") } } } export function install (_Vue){ Vue = _Vue const _init = Vue.prototype._init; Vue.prototype._init = function(options){ options = options || {} if(options.store){ this.$store = options.store }else if(options.parent && options.parent.$store){ this.$store = options.parent.$store } _init.call(this,options) } } export default { Store,install }
到此為止 測(cè)試頁(yè)面的+ -count功能應(yīng)該是沒(méi)有問(wèn)題了
當(dāng)點(diǎn)擊后面兩個(gè)方法,發(fā)現(xiàn)會(huì)有報(bào)錯(cuò)
這個(gè)什么原因呢? 調(diào)試也可以發(fā)現(xiàn),作用域的問(wèn)題,調(diào)用不了vuex里面的對(duì)象
const dispatch = this.dispatch this.dispatch = (...args) =>{ dispatch.apply(this,args) }
完整代碼
import { createAction, mergeObjects } from "./util" let Vue //存儲(chǔ)Vue變量。一是為了注入$store到各個(gè)Vue組件,二是后續(xù)要用到Vue的雙向綁定的功能 export class Store{ constructor ({ state = {}, actions = {}, mutations = {} }){ //加上這個(gè),解決在外面調(diào)用dispatch的問(wèn)題 const dispatch = this.dispatch this.dispatch = (...args) =>{ dispatch.apply(this,args) } //依賴vue雙向綁定 this._vm = new Vue({ data : state }) this.actions = Object.create(null) //構(gòu)造下action。兼容字符串和function兩種模式 this._setupActions(actions); //構(gòu)造mutations this._setupMutations(mutations); } get state (){ //頁(yè)面中通過(guò)此方法獲取state return this._vm._data; } set state (v){ throw new Error("[Vuex] vuex root state is read only.") } _setupActions (actions){ this._actions = Object.create(null); actions = Array.isArray(actions) ? mergeObjects(actions) : actions; Object.keys(actions).forEach(name =>{ this._actions[name] = createAction(actions[name],this); //兼容string 和function的寫法 if(!this.actions[name]){ this.actions[name] = (...args) =>this._actions[name](...args) } }) } _setupMutations(mutations){ this._mutations = Array.isArray(mutations) ? mergeObjects(mutations,true) : mutations } /** * 執(zhí)行mutation */ dispatch (type,...payload) { const mutation = this._mutations[type]; const state = this.state; if(mutation){ this._dispatching = true if(Array.isArray(mutation)){ //遍歷執(zhí)行 mutation.forEach(m =>m(state,...payload)) }else{ mutation(state,...payload) } this._dispatching = false }else{ console.warn("[vuex] unknown mutation:${type}") } } } export function install (_Vue){ Vue = _Vue const _init = Vue.prototype._init; Vue.prototype._init = function(options){ options = options || {} if(options.store){ this.$store = options.store }else if(options.parent && options.parent.$store){ this.$store = options.parent.$store } _init.call(this,options) } } export default { Store,install }
只此。VUEX的基本功能已完成了
以上代碼都來(lái)至vuex 0.3
我不生成代碼,只做代碼的搬運(yùn)工
測(cè)試代碼在這里
https://github.com/denditang/...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/85004.html
摘要:此文章用于記錄本人學(xué)習(xí)歷程,有共同愛(ài)好者可加好友一起分享。從上周天,由于本周有公司籃球比賽,所以耽誤兩天晚上,耗時(shí)三個(gè)晚上勉強(qiáng)做了一個(gè)登錄功能。這里的用戶信息和登錄狀態(tài)都是直接取的中的用戶信息進(jìn)行屬性值初始化。 此文章用于記錄本人VUE學(xué)習(xí)歷程,有共同愛(ài)好者可加好友一起分享。從上周天,由于本周有公司籃球比賽,所以耽誤兩天晚上,耗時(shí)三個(gè)晚上勉強(qiáng)做了一個(gè)登錄功能。中間的曲折只有自己知道,有...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...
摘要:那該怎么管理這兩個(gè)不同的項(xiàng)目呢解決子模塊用的的同學(xué)肯定一下子就想到子模塊的知識(shí)了。最后,也希望有想法的同學(xué)還有大佬多多留言,給點(diǎn)建議原文地址從零開始做前端架構(gòu)腳手架參考資料官方文檔使用定制前端腳手架別人寫的腳手架文件操作相關(guān)文檔子模塊 前言 相信很多人都用過(guò)vue-cli或create-react-app或者類似的腳手架。腳手架方便我們復(fù)制,粘貼,或者clone代碼庫(kù),而且還可以更具用...
閱讀 2199·2023-04-25 17:48
閱讀 3652·2021-09-22 15:37
閱讀 2989·2021-09-22 15:36
閱讀 6143·2021-09-22 15:06
閱讀 1695·2019-08-30 15:53
閱讀 1496·2019-08-30 15:52
閱讀 780·2019-08-30 13:48
閱讀 1186·2019-08-30 12:44