如何手寫一個(gè)簡(jiǎn)易的 Vuex
前言
本文適合使用過 Vuex 的人閱讀,來了解下怎么自己實(shí)現(xiàn)一個(gè) Vuex。
基本骨架
這是本項(xiàng)目的src/store/index.js文件,看看一般 vuex 的使用
import Vue from 'vue'
import Vuex from './myvuex' // 引入自己寫的 vuex
import * as getters from './getters'
import * as actions from './actions'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex) // Vue.use(plugin)方法使用vuex插件
// vuex 導(dǎo)出一個(gè)類叫Store,并傳入對(duì)象作為參數(shù)
export default new Vuex.Store({
state,
mutations,
actions,
getters,
})
Vue.use的用法:
安裝 Vue.js 插件。如果插件是一個(gè)對(duì)象,必須提供 install 方法。如果插件是一個(gè)函數(shù),它會(huì)被作為 install 方法。install 方法調(diào)用時(shí),會(huì)將 Vue 作為參數(shù)傳入。這個(gè)方法的第一個(gè)參數(shù)是 Vue 構(gòu)造器,第二個(gè)參數(shù)是一個(gè)可選的選項(xiàng)對(duì)象。
- 該方法需要在調(diào)用 new Vue() 之前被調(diào)用。
- 當(dāng) install 方法被同一個(gè)插件多次調(diào)用,插件將只會(huì)被安裝一次。
即是我們需要在./myvuex.js中導(dǎo)出 install方法,同時(shí)導(dǎo)出一個(gè)類Store,于是第一步可以寫出代碼:
let Vue = null
class Store {
constructor(options) {}
}
function install(_Vue) {
Vue = _Vue // 上面Store類需要能獲取到Vue
}
export default {
Store,
install,
}
install 方法
當(dāng)我們使用 vuex 的時(shí)候,每一個(gè)組件上面都有一個(gè)this.$store屬性,里面包含了 state,mutations, actions, getters 等,所以我們也需要在每個(gè)組件上都掛載一個(gè)$store 屬性,要讓每一個(gè)組件都能獲取到,這里我們使用Vue.mixin(mixin),用法介紹如下:
全局注冊(cè)一個(gè)混入,影響注冊(cè)之后所有創(chuàng)建的每個(gè) Vue 實(shí)例??梢允褂没烊胂蚪M件注入自定義的行為,它將影響每一個(gè)之后創(chuàng)建的 Vue 實(shí)例。
function install(_Vue) {
Vue = _Vue // install方法調(diào)用時(shí),會(huì)將Vue作為參數(shù)傳入(上面Store類需要用到Vue)
// 實(shí)現(xiàn)每一個(gè)組件,都能通過this調(diào)用$store
Vue.mixin({
beforeCreate() {
// 通過this.$options可以獲取new Vue({參數(shù)}) 傳遞的參數(shù)
if (this.$options && this.$options.store) {
// 證明這個(gè)this是根實(shí)例,也就是new Vue產(chǎn)生的那個(gè)實(shí)例
this.$store = this.$options.store
} else if (this.$parent && this.$parent.$store) {
// 子組件獲取父組件的$store屬性
this.$store = this.$parent.$store
}
},
})
}
state
由于 Vuex 是基于 Vue 的響應(yīng)式原理基礎(chǔ),所以我們要讓數(shù)據(jù)改變可刷新視圖,則需要?jiǎng)?chuàng)建一個(gè) vue 實(shí)例
class Store {
// options 即是 Vuex.Store({})傳入的參數(shù)
constructor(options) {
// vuex 的核心就是借用了vue的實(shí)例,因?yàn)関ue的實(shí)例數(shù)據(jù)變化,會(huì)刷新視圖
let vm = new Vue({
data: {
state: options.state,
},
})
// state
this.state = vm.state
}
}
commit
我們使用 vuex 改變數(shù)據(jù)時(shí),是觸發(fā) commit 方法,即是這樣使用的:
this.$store.commit('eventName', '參數(shù)' );
所以我們要實(shí)現(xiàn)一個(gè)commit方法,把 Store 構(gòu)造函數(shù)傳入的 mutations 做下處理
class Store {
constructor(options) {
// 實(shí)現(xiàn) state ...
// mutations
this.mutations = {} // 存儲(chǔ)傳進(jìn)來的mutations
let mutations = options.mutations || {}
// 循環(huán)取出事件名進(jìn)行處理(mutations[事件名]: 執(zhí)行方法)
Object.keys(mutations).forEach(key => {
this.mutations[key] = params => {
mutations[key].call(this, this.state, params) // 修正this指向
}
})
}
commit = (key, params) => {
// key為要觸發(fā)的事件名
this.mutations[key](params)
}
}
dispatch
跟上面的 commit 流程同理
class Store {
constructor(options = {}) {
// ...
// actions
this.actions = {}
let actions = options.actions || {}
Object.keys(actions).forEach(key => {
this.actions[key] = params => {
actions[key].call(this, this, params)
}
})
}
dispatch = (type, payload) => {
this.actions[type](payload)
}
}
getters
getters 實(shí)際就是返回 state 的值,在使用的時(shí)候是放在 computed 屬性,每一個(gè) getter 都是函數(shù)形式;
getters 是需要雙向綁定的。但不需要雙向綁定所有的 getters,只需要綁定項(xiàng)目中事件使用的 getters。
這里使用Object.defineProperty()方法,它會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回此對(duì)象。
class Store {
constructor(options = {}) {
// ...
// getters
this.getters = {}
let getters = options.getters || {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key].call(this, this.state)
},
})
})
}
}
到此為止,已經(jīng)可以使用我們自己寫的 vuex 做一些基本操作了,但只能通過this.$store.xx的形式調(diào)用,故需要再實(shí)現(xiàn)方法。
map 輔助函數(shù)
先來說說 mapState
沒有 map 輔助函數(shù)之前這樣使用:
computed: {
count () {
return this.$store.state.count
}
}
當(dāng)映射的計(jì)算屬性的名稱與 state 的子節(jié)點(diǎn)名稱相同時(shí),給 mapState 傳一個(gè)字符串?dāng)?shù)組。
computed: {
// 使用對(duì)象展開運(yùn)算符將此對(duì)象混入到外部對(duì)象中
...mapState(['count'])
}
我們這里簡(jiǎn)單就只實(shí)現(xiàn)數(shù)組的情況
export const mapState = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.state[item]
}
})
return obj
}
之后幾個(gè) map 輔助函數(shù)都是類似
- mapGetters
export const mapGetters = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.getters[item]
}
})
return obj
}
- mapMutations
export const mapMutations = args => {
let obj = {}
args.forEach(item => {
obj[item] = function(params) {
return this.$store.commit(item, params)
}
})
return obj
}
- mapActions
export const mapActions = args => {
let obj = {}
args.forEach(item => {
obj[item] = function(payload) {
return this.$store.dispatch(item, payload)
}
})
return obj
}
完整代碼
let Vue = null
class Store {
constructor(options) {
// vuex 的核心就是借用了vue的實(shí)例,因?yàn)関ue的實(shí)例數(shù)據(jù)變化,會(huì)刷新視圖
let vm = new Vue({
data: {
state: options.state,
},
})
// state
this.state = vm.state
// mutations
this.mutations = {} // 存儲(chǔ)傳進(jìn)來的mutations
let mutations = options.mutations || {}
Object.keys(mutations).forEach(key => {
this.mutations[key] = params => {
mutations[key].call(this, this.state, params)
}
})
// actions
this.actions = {}
let actions = options.actions || {}
Object.keys(actions).forEach(key => {
this.actions[key] = params => {
actions[key].call(this, this, params)
}
})
// getters
this.getters = {}
let getters = options.getters || {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key].call(this, this.state)
},
})
})
}
commit = (key, params) => {
this.mutations[key](params)
}
dispatch = (type, payload) => {
this.actions[type](payload)
}
}
export const mapState = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.state[item]
}
})
return obj
}
export const mapGetters = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.getters[item]
}
})
return obj
}
export const mapMutations = args => {
let obj = {}
args.forEach(item => {
obj[item] = function(params) {
return this.$store.commit(item, params)
}
})
return obj
}
export const mapActions = args => {
let obj = {}
args.forEach(item => {
obj[item] = function(payload) {
return this.$store.dispatch(item, payload)
}
})
return obj
}
function install(_Vue) {
Vue = _Vue // install方法調(diào)用時(shí),會(huì)將Vue作為參數(shù)傳入(上面Store類需要用到Vue)
// 實(shí)現(xiàn)每一個(gè)組件,都能通過this調(diào)用$store
Vue.mixin({
beforeCreate() {
// 通過this.$options可以獲取new Vue({參數(shù)}) 傳遞的參數(shù)
if (this.$options && this.$options.store) {
// 證明這個(gè)this是根實(shí)例,也就是new Vue產(chǎn)生的那個(gè)實(shí)例
this.$store = this.$options.store
} else if (this.$parent && this.$parent.$store) {
// 子組件獲取父組件的$store屬性
this.$store = this.$parent.$store
}
},
})
}
export default {
Store,
install,
}
以上就是如何手寫一個(gè)簡(jiǎn)易的 Vuex的詳細(xì)內(nèi)容,更多關(guān)于手寫 vuex的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue使用v-model收集各種表單數(shù)據(jù)、過濾器的示例詳解
這篇文章主要介紹了Vue使用v-model收集各種表單數(shù)據(jù)、過濾器的示例,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
詳解基于Vue/React項(xiàng)目的移動(dòng)端適配方案
這篇文章主要介紹了詳解基于Vue/React項(xiàng)目的移動(dòng)端適配方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
詳解Webstorm 新建.vue文件支持高亮vue語法和es6語法
這篇文章主要介紹了Webstorm 添加新建.vue文件功能并支持高亮vue語法和es6語法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10
Vue如何實(shí)現(xiàn)利用vuex永久儲(chǔ)存數(shù)據(jù)
這篇文章主要介紹了Vue如何實(shí)現(xiàn)利用vuex永久儲(chǔ)存數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
vue組件中iview的modal組件爬坑問題之modal的顯示與否應(yīng)該是使用v-show
這篇文章主要介紹了vue組件中iview的modal組件爬坑問題之modal的顯示與否應(yīng)該是使用v-show,本文通過實(shí)例圖文相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
深入理解Vue.js3中Reactive的實(shí)現(xiàn)
reactive是Vue 3的Composition API中的一個(gè)函數(shù),它允許你創(chuàng)建一個(gè)響應(yīng)式的數(shù)據(jù)對(duì)象,本文主要介紹了深入理解Vue.js3中Reactive的實(shí)現(xiàn),感興趣的可以了解一下2024-01-01
Vue3.0使用ref和reactive來創(chuàng)建響應(yīng)式數(shù)據(jù)
ref?和?reactive?是?Composition?API?中用來創(chuàng)建響應(yīng)式數(shù)據(jù)的兩個(gè)核心函數(shù),在本篇文章中,我們將詳細(xì)講解如何使用?ref?和?reactive?來創(chuàng)建響應(yīng)式數(shù)據(jù),并展示它們之間的區(qū)別和使用場(chǎng)景,需要的朋友可以參考下2024-11-11

