如何手寫一個(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)文章
BuildAdmin elementPlus自定義表頭添加tooltip方法示例
這篇文章主要介紹了BuildAdmin elementPlus 自定義表頭,添加tooltip實(shí)現(xiàn)方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Vue進(jìn)階之利用transition標(biāo)簽實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Vue如何利用transition標(biāo)簽實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)動(dòng)畫,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起一下2023-08-08
WebStorm啟動(dòng)vue項(xiàng)目報(bào)錯(cuò)代碼:1080?throw?err解決辦法
在使用webstorm新建vue項(xiàng)目時(shí)常會(huì)遇到一些報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于WebStorm啟動(dòng)vue項(xiàng)目報(bào)錯(cuò)代碼:1080?throw?err的解決辦法,文中將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
如何使用vue開發(fā)公眾號(hào)網(wǎng)頁(yè)
因?yàn)轫?xiàng)目需要,近期做了一個(gè)公眾號(hào)網(wǎng)頁(yè)開發(fā)。在此期間也踩了一些坑,解決這些坑之后,準(zhǔn)備對(duì)這個(gè)項(xiàng)目進(jìn)行復(fù)盤。記錄下項(xiàng)目從開發(fā)到上線所解決的問題,并對(duì)使用vue進(jìn)行公眾號(hào)開發(fā)的步驟進(jìn)行一個(gè)總結(jié)。方便以后有問題進(jìn)行查閱。希望對(duì)你有所幫助2021-05-05
uniapp使用webview內(nèi)嵌H5的注意事項(xiàng)詳解
在移動(dòng)應(yīng)用開發(fā)中,uniApp框架提供了一種跨平臺(tái)的解決方案,允許開發(fā)者使用一套代碼來構(gòu)建iOS、Android等多平臺(tái)的應(yīng)用,這篇文章主要給大家介紹了關(guān)于uniapp使用webview內(nèi)嵌H5的注意事項(xiàng),需要的朋友可以參考下2024-07-07
基于vue-cli npm run build之后vendor.js文件過大的解決方法
今天小編就為大家分享一篇基于vue-cli npm run build之后vendor.js文件過大的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue-cli創(chuàng)建的項(xiàng)目中的gitHooks原理解析
這篇文章主要介紹了vue-cli創(chuàng)建的項(xiàng)目中的gitHooks原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
基于Vue+element-ui 的Table二次封裝的實(shí)現(xiàn)
這篇文章主要介紹了基于Vue+element-ui 的Table二次封裝的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07

