您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“vuex的實現(xiàn)原理是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“vuex的實現(xiàn)原理是什么”吧!
關(guān)于vuex
就不再贅述,簡單回顧一下:當(dāng)應(yīng)用碰到多個組件共享狀態(tài)
時,簡單的單向數(shù)據(jù)流
很容易被破壞:第一,多個視圖依賴于同一狀態(tài);第二,來自不同視圖的行為需要變更同一狀態(tài)。若解決前者使用傳參的方式,則不適用于多層嵌套的組件以及兄弟組件;若解決后者使用父子組件直接引用或事件變更和同步狀態(tài)的多份拷貝,則不利于代碼維護。
所以,最好的辦法是:把組件的共享狀態(tài)抽取出,以一個全局單例模式管理!這也正是vuex
背后的基本思想。
所以,vuex的大致框架如下:
class Store {
constructor() {
// state
// getters
// mutations
// actions
}
// commit
// dipatch
}
接下來,就寫寫看。
vue create vue2-vuex//創(chuàng)建vue2項目
yarn add vuex@next --save//安裝vuex
yarn serve//啟動項目
1、State
(1)使用
//store.js
// 倉庫
import Vue from 'vue'
import Vuex from 'vuex'
import extra from './extra.js'
Vue.use(Vuex) //引入vuex的方式,說明Store需要install方法
export default new Vuex.Store({
// 倉庫數(shù)據(jù)源
state: {
count: 1,
dowhat: 'addCount'
},
}
//app.vue
<template>
<div class="testState">
<p>{{mycount}}</p>
<p>{{dowhat}}:{{count}}</p>
</div>
</template>
<script>
export default {
import {
mapState
} from 'vuex'
// 推薦方式
computed: mapState()({
mycount: state => state.count
}),
// 推薦方式的簡寫方式
computed: {
// 解構(gòu)的是getters
...mapState(['count', 'dowhat'])
},
}
</script>
(2)注意
由于 Vuex 的狀態(tài)存儲是響應(yīng)式的,從 store 實例中讀取狀態(tài)最簡單的方法就是在計算屬性
中返回某個狀態(tài),這種模式導(dǎo)致組件依賴全局狀態(tài)單例
。在模塊化的構(gòu)建系統(tǒng)中,在每個需要使用 state 的組件中需要頻繁地導(dǎo)入,并且在測試組件時需要模擬狀態(tài)
Vuex 通過 store
選項,提供了一種機制將狀態(tài)從根組件“注入”到每一個子組件中(需調(diào)用 Vue.use(Vuex)
)
(3)實現(xiàn)
所以除了Store
內(nèi)部的五大屬性以外,還需要考慮插件的一個install
方法,所以大致框架如下:
class Store {
constructor() {
// state
// getters
// mutations
// actions
//modules
}
// commit
// dipatch
}
let Vuex = {
Store,
Install
}
export default Vuex
所以,接下來就可以具體實現(xiàn)了,
class Store {
constructor(options) {
// state
this.state = options.state
}
}
let install = function(_Vue) {
_Vue.mixin({
beforeCreate() { //在組件創(chuàng)建之前自動調(diào)用,每個組件都有這個鉤子
if (this.$options && this.$options.store) { //this.$options讀取根組件
this.$store = this.$options.store
} else {
this.$store = this.$parent && this.$parent.$store
}
}
})
}
然而,上述的state的實現(xiàn)有一個缺點:當(dāng)改變數(shù)據(jù)的時候,state
的數(shù)據(jù)不能動態(tài)的渲染。所以如何把state
里的數(shù)據(jù)成為響應(yīng)式成為關(guān)鍵問題?實際上,類似vue
里的data
,也可以通過這種方式讓其成為響應(yīng)式。那么就得從install
方法中傳入Vue
,所以改變后:
let Vue=null
class Store {
constructor(options) {
// state
this.vm = new _Vue({
data: {
state: options.state//data中的數(shù)據(jù)才是響應(yīng)式
}
})
}
get state() {
return this.vm.state
}
}
let install = function(_Vue) {//用于Vue.use(plugin)
Vue=_Vue
_Vue.mixin({
onBeforeCreate() { //在組件創(chuàng)建之前自動調(diào)用,每個組件都有這個鉤子
if (this.$options && this.$options.store) { //this.$options讀取根組件
this.$store = this.$options.store
} else {
this.$store = this.$parent && this.$parent.$store
}
}
})
}
2、getters
(1)使用
//store.js
export default new Vuex.Store({
// 計算屬性
getters: {
// 這里的函數(shù)不需要調(diào)用,可以直接使用,官方默認前面有g(shù)et
getCount(state) {//接受 state 作為其第一個參數(shù)
return state.count * 100;
}
},
}
(2)注意
有時候我們需要從 store 中的 state 中派生出一些狀態(tài)(比如增加,刪除,過濾等等),Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會被重新計算,Getter 接受 state 作為其第一個參數(shù),getter 在通過方法訪問時,每次都會去進行調(diào)用,而不會緩存結(jié)果
(3)實現(xiàn)
// getters
let getters = options.getters || {}
this.getters = {}
Object.keys(getters).forEach(getterName => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getters[getterName](this.state)
}
})
})
3、mutations
(1)使用
//store.js
export default new Vuex.Store({
// 相當(dāng)于methods
mutations: {
// mutations內(nèi)部的函數(shù),天生具備一個形參
add(state, n) {
state.count += n;
},
decrease(state, n) {
state.count -= n;
}
},
}
methods: {
submit() {
console.log('success');
},
// 解構(gòu)倉庫mutations里面的方法,要啥解構(gòu)啥
...mapMutations(['add', 'decrease']),
// this.$store.commit('add'),
...mapActions(['addAction', 'decreaseAction']),
// this.addAction()調(diào)用actions里面的方法
// this.$store.dispatch('add'),
}
(2)注意
更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。Vuex 中的 mutation 類似于事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler) 。這個回調(diào)函數(shù)就是進行狀態(tài)更改的地方,并且它會接受 state 作為第一個參數(shù),不能直接調(diào)用一個 mutation handler。這個選項更像是事件注冊:“當(dāng)觸發(fā)一個類型為 increment
的 mutation 時,調(diào)用此函數(shù)?!币獑拘岩粋€ mutation handler,你需要以相應(yīng)的 type 調(diào)用 store.commit 方法
可以向 store.commit
傳入額外的參數(shù),即 mutation 的 載荷(payload) ,在大多數(shù)情況下,載荷應(yīng)該是一個對象,這樣可以包含多個字段并且記錄的 mutation 會更易讀
(3)實現(xiàn)
// mutations
let mutations = options.mutations || {}
this.mutations = {}
Object.keys(mutations).forEach(mutationName => {
this.mutations[mutationName] = (arg) => {//保證多個(第二個)參數(shù)的傳入
mutations[mutationName](this.state, arg)
}
})
commit = (method, arg) => {//使用箭頭函數(shù)改變被調(diào)用的this的指向
// console.log(this);
this.mutations[method](arg)
}
4、actions
(1)使用
//store.js
export default new Vuex.Store({
actions: {
addAction(context) {
// 在這里調(diào)用add方法
context.commit('add', 10);
},
decreaseAction({
commit
}) {
commit('decreaseAction', 5)
}
},
}
(2)注意
Action 提交的是 mutation,而不是直接變更狀態(tài)。
Action 可以包含任意異步操作
Action 函數(shù)接受一個與 store 實例具有相同方法和屬性的 context 對象
Action 通過 store.dispatch
方法觸發(fā)
Action 通常是異步的,store.dispatch
可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise,并且 store.dispatch
仍舊返回 Promise
一個 store.dispatch
在不同模塊中可以觸發(fā)多個 action 函數(shù)。在這種情況下,只有當(dāng)所有觸發(fā)函數(shù)完成后,返回的 Promise 才會執(zhí)行
(3)實現(xiàn)
// actions
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach(actionName => {
this.actions[actionName] = (arg) => {
actions[actionName](this, arg)
}
})
dispatch=(method, arg) =>{
this.actions[method](arg)
}
5、modules
(1)使用
// actions
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach(actionName => {
this.actions[actionName] = (arg) => {
actions[actionName](this, arg)
}
})
dispatch=(method, arg) =>{
this.actions[method](arg)
}
//store.js
modules: {
extra: extra
}
(2)注意
由于使用單一狀態(tài)樹,應(yīng)用的所有狀態(tài)會集中到一個比較大的對象。當(dāng)應(yīng)用變得非常復(fù)雜時,store 對象就有可能變得相當(dāng)臃腫,Vuex 允許我們將 store 分割成模塊(module) 。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割
對于模塊內(nèi)部的 mutation 和 getter,接收的第一個參數(shù)是模塊的局部狀態(tài)對象
對于模塊內(nèi)部的 action,局部狀態(tài)通過 context.state
暴露出來,根節(jié)點狀態(tài)則為 context.rootState
對于模塊內(nèi)部的 getter,根節(jié)點狀態(tài)(rootState)會作為第三個參數(shù)暴露出來
let Vue = null//全局的_Vue
class Store {
constructor (options) {
// state
//this.state = options.state 寫法不完美,當(dāng)改變數(shù)據(jù)的時候,不能動態(tài)的渲染,所以需要把data中的數(shù)據(jù)做成響應(yīng)式的
this.vm = new _Vue({
data: {
state: options.state//data中的數(shù)據(jù)才是響應(yīng)式
}
})
// getters
let getters = options.getters || {}
this.getters = {}
Object.keys(getters).forEach(getterName => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return getters[getterName](this.state)
}
})
})
// mutations
let mutations = options.mutations || {}
this.mutations = {}
Object.keys(mutations).forEach(mutationName => {
this.mutations[mutationName] = (arg) => {//保證多個(第二個)參數(shù)的傳入
mutations[mutationName](this.state, arg)
}
})
// actions
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach(actionName => {
this.actions[actionName] = (arg) => {
actions[actionName](this, arg)
}
})
}
dispatch=(method, arg) =>{
this.actions[method](arg)
}
commit = (method, arg) => {
// console.log(this);
this.mutations[method](arg)
}
get state() {
return this.vm.state
}
}
let install = function(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {//在組件創(chuàng)建之前自動調(diào)用,每個組件都有這個鉤子
if (this.$options && this.$options.store) { // this.$options讀取到根組件
this.$store = this.$options.store
} else { // //如果不是根組件的話,也把$store掛到上面,因為是樹狀組件
this.$store = this.$parent && this.$parent.$store
}
}
})
}
let Vuex = {
Store,
install
}
export default Vuex
到此,相信大家對“vuex的實現(xiàn)原理是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。