




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
教學目標掌握Vuex的工作原理。掌握Vuex五個核心概念。掌握Vuex中mutation和action的定義與使用方法。熟悉多模塊的應用場景。學會在Vue3.x中引入相關VuexAPI、使用store對象。1第9章-狀態(tài)管理模式Vuex(4學時)29.1Vuex概述
1.狀態(tài)管理模式Vuex是一個專為Vue.js應用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應用的所有組件的State狀態(tài),并以相應的規(guī)則保證狀態(tài)以一種可預測的方式發(fā)生變化。
Vuex也集成到Vue的官方調試工具devtoolsextension,提供了諸如零配置的time-travel調試、狀態(tài)快照導入導出等高級調試功能。
狀態(tài)自管理應用通常包含state、view和actions三個部分,如圖所示。它們作用分別如下:state(狀態(tài)):驅動應用的數(shù)據(jù)源。數(shù)據(jù)源就是組件里面的data。view(視圖):以聲明方式將state映射到視圖。{{count}}即為聲明方式,數(shù)據(jù)就可以顯示出來。actions(行為):響應在view上的用戶輸入導致的狀態(tài)變化。actions其實就是多個函數(shù)。9.1.1Vuex定義【例9-1】簡易投票的單向數(shù)據(jù)流應用實戰(zhàn)。39.1.1Vuex定義
第16~22行定義template屬性,使用反單引號定義div標記,該標記包含文本插值和一個按鈕,用于觸發(fā)遞增行為來改變count的值,并顯示在視圖上。
第24行定義methods屬性,其中定義vote()方法實現(xiàn)tickets增1。view初始讀取data中的tickets,顯示為0。通過事件觸發(fā)調用actions里面的vote()方法,然后actions去更新state的狀態(tài)數(shù)據(jù)。state更新之后,view的界面也會隨之改變。42.Vuex數(shù)據(jù)流向及適用場景
在實際工程應用中經(jīng)常會遇到多組件間共享狀態(tài),此時單向數(shù)據(jù)流的簡潔性很容易被破壞。主要來源于兩種應用場合:使用數(shù)據(jù):多個視圖依賴于同一狀態(tài)。
在多層嵌套的組件中采用參數(shù)傳遞的方法將會非常繁瑣,尤其是兄弟組件間的狀態(tài)傳遞更顯得無能為力。更新數(shù)據(jù):來自不同視圖的行為需要變更同一狀態(tài)。9.1.1Vuex定義
經(jīng)常會采用父子組件直接引用或者通過事件來變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱,通常會導致代碼無法維護。
如果不打算開發(fā)大型單頁應用,就沒有必要使用Vuex。一個簡單的store模式就足夠滿足需求了。但是,如果需要構建一個中大型單頁應用,此時很可能會考慮如何更好地在組件外部管理狀態(tài),Vuex自然而然將會成為最好的選擇。5
若有一個狀態(tài)需要被多個實例共享,可以簡單地通過維護一份數(shù)據(jù)來實現(xiàn)共享,這就是store模式。
【例9-2】store模式應用實戰(zhàn)--共享狀態(tài)。設計要求:設置兩個組件分別共享store中state狀態(tài),同時管理自身的私有數(shù)據(jù),通過全局聲明一個store對象變量,封裝一個state屬性(定義為reactive()響應式對象)和setMessageAction(newValue)、clearMessageAction()等兩個方法。再定義兩個組件,分別為App1、App2,并給每個實例分別定義data、methods等屬性。data屬性中分別定義私有數(shù)據(jù)屬性privateState和共享數(shù)據(jù)屬性sharedState,并將sharedState屬性的值設置為store.state。9.1.2簡單狀態(tài)管理-store模式69.1.2簡單狀態(tài)管理-store模式
代碼中第27~40行定義1個對象變量store,并給其定義一個state屬性(在其中定義message屬性,作為狀態(tài)數(shù)據(jù))和setMessageAction(newValue)(功能為改變狀態(tài))、clearMessageAction()(功能為清空狀態(tài))等兩個方法。
兩個Vue實例中data屬性中均定義了privateState(私有數(shù)據(jù))、sharedState(共享數(shù)據(jù))。7
store模式應用-單擊“改變共享信息”按鈕頁面store模式應用-單擊“清空享信息”按鈕頁面9.1.2簡單狀態(tài)管理-store模式注意:所有store中state的改變,都放置在store自身的action中去管理。這種集中式狀態(tài)管理能夠被更容易地理解哪種類型的mutation將會發(fā)生,以及它們是如何被觸發(fā)。當出現(xiàn)錯誤時,現(xiàn)在也會有一個log記錄bug之前發(fā)生了什么。此外,每個實例/組件仍然可以擁有和管理自己的私有狀態(tài)(數(shù)據(jù))。89.2Vuex基本使用
在項目中需要使用Vuex時,必須將vue.js和vuex.js引用到項目中??梢酝ㄟ^CDN或者script腳本引用(
/vuex@4.1.0/dist/vuex.global.js),然后在項目中安裝vuex模塊,并在項目主文件中導入vue和vuex,再顯式地使用app.use(store)即可。具體的操作步驟如下:1.直接下載/CDN引用。HTML中使用script標簽引入。<scriptsrc="vue.global.js"></script><scriptsrc="vuex.global.js"></script>CDN引用。<scriptsrc="/vuex@4.1.0/dist/vuex.global.js"></script>
2.項目目錄下載安裝模塊。npminstallvuex--save-dev|-D
3.導入并顯式地使用Vuex。//index.jsimportVuefrom'vue'importVuexfrom'vuex'Vue.use(Vuex)//Vue2.x中顯式地通過
Vue.use()
來使用Vuex//在Vue3.x中使用方式import{createApp}from'vue'importAppfrom'./App.vue'importstorefrom'./store'Vue.createApp(App).use(store).mount('#app')99.2Vuex基本使用4.Vue3.x中的Vuex
在Vue3.x中使用Vuex的版本是v4.0.2以上,在src/store/index.js文件中需要導入createStoreAPI,然后定義state、mutations、actions、modules等核心屬性。部分參考代碼如下:import
{
createStore
}
from
'vuex'
export
default
createStore({
state:
{
user:
{name:
'李小明',sex:
'男'},
title:
'Vuex狀態(tài)管理'
},
mutations:
{
setUserName(state,
value)
{
=
value
}
},
actions:
{},
modules:
{}
})
在Vue3.x中,組件內使用Vuex,setup函數(shù)中使用有所不同。部分參考代碼如下:import
{
toRefs,reactive}
from
"vue";
import
{
useStore}
from
"vuex";
export
default
{
setup()
{
const
state
=
reactive({
name:
'',
title:''
})
const
store
=
useStore()
=
return
{
...toRefs(state)
...toRefs(store.state.user)
}
}
};
在Vue3.x中使用Vuex時需要顯式導入useStore,然后在setup函數(shù)內通過useStore()來創(chuàng)建store(如第9行所示),并在其中定義相關方法去調用相關的mutations和actions,最后將store.state中的相關屬性通過toRefs()轉換為普通的響應式數(shù)據(jù)(如第13行所示),供模板使用。109.3Vuex核心概念
Vuex應用的核心就是store(倉庫)。store就是一個容器,它包含著用戶應用中大部分的狀態(tài)(數(shù)據(jù)),如右圖所示。但Vuex和單純的全局對象是不同。
主要有兩點區(qū)別:
Vuex的狀態(tài)存儲是響應式的。
當Vue實例/組件從store中讀取狀態(tài)的時候,若store中的狀態(tài)發(fā)生變化,那么相應的實例/組件也會相應地得到高效更新。
用戶不能直接改變store中的狀態(tài)。
改變store中的狀態(tài)的唯一途徑就是顯式地提交mutation。
這樣使得可以方便地跟蹤每一個狀態(tài)的變化,從而可以通過一些工具幫助用戶更好地了解自己的應用。119.3.1一個完整的store結構
一個完整的store包含state、getters、mutations、actions、modules等五大組成部分。精簡的代碼如下所示。//Vue3.x中定義方式import
{
createStore
}
from
'vuex'
export
default
createStore({
state:
{
//
存放狀態(tài)
},
getters:
{
//
state的計算屬性
},
mutations:
{
//
更改state中狀態(tài)的邏輯,同步操作
}
actions:
{
//
提交mutation,異步操作
}
//
如果將store分成一個個的模塊的話,則需要用到modules。
//
然后在每一個module中寫state,
getters,
mutations,
actions等。
modules:
{
a:
moduleA,
b:
moduleB,
//
...
})
需要使用exportdefaultcreateStore({})將store導出,在main.js文件可以導入,并掛載到Vue根實例中,其它子組件即可以使用store中的state狀態(tài)。129.3.2最簡單的store
安裝Vuex之后,就可以來創(chuàng)建一個store。創(chuàng)建過程比較簡單,僅需要提供一個初始state對象和一些mutation。部分代碼如下:import
{createStore}
from
'vuex'
exportdefaultcreateStore({
state:
{
count:
0
},
mutations:
{
increment
(state)
{
state.count++
}
}
})
接下來就可以通過store.state來獲取狀態(tài)對象,以及通過mit方法觸發(fā)狀態(tài)變更,并通過控制臺輸出狀態(tài)數(shù)據(jù)。代碼如下:mit('increment')//increment觸發(fā)mutationconsole.log(store.state.count)//count值為1注意:通過提交mutation的方式,而非直接改變store.state.count,是因為想要更明確地追蹤到狀態(tài)的變化。這樣可使用戶的意圖更加明顯,在閱讀代碼的時候能更容易地解讀應用內部的狀態(tài)改變。由于store中的狀態(tài)是響應式的,在組件中調用store中的狀態(tài)簡單到僅需要在計算屬性中返回即可。觸發(fā)變化也僅僅是在組件的methods中提交mutation。139.3.2最簡單的storeVuex是解決Vue組件和組件間相互通信而存在的。Vuex理解起來稍微復雜,可以通過以下五個核心概念來了解并學會使用。它們分別是:state:定義狀態(tài)(變量),輔助函數(shù)mapState。getter:獲取狀態(tài)(變量的值),同時可以對狀態(tài)進行處理,輔助函數(shù)mapGetters。mutation:修改狀態(tài)(修改變量的值),輔助函數(shù)mapMutations。action:觸發(fā)mutation函數(shù),從而修改狀態(tài),支持異步,輔助函數(shù)mapActions。module:在狀態(tài)很多時,把狀態(tài)分開來管理。149.3.3Vuex中stateVuex使用單一狀態(tài)樹,即用一個對象包含了全部的應用層級狀態(tài),它作為一個“唯一數(shù)據(jù)源”而存在。
單一狀態(tài)樹讓用戶能夠直接地定位任一特定的狀態(tài)片段,在調試的過程中也能輕易地取得整個當前應用狀態(tài)的快照。
存儲在Vuex中的數(shù)據(jù)和Vue實例中的data遵循相同的規(guī)則,都是純粹的對象(有零個或多個的key/value對)。
1.在Vue組件中通過computed計算屬性獲得Vuex狀態(tài)
在Vue組件中如何展示狀態(tài)呢?由于Vuex的狀態(tài)存儲是響應式的,從store實例中讀取狀態(tài)最簡單的方法就是在計算屬性computed中返回某個狀態(tài)。
部分代碼如下://
創(chuàng)建一個
Counter
組件
const
Counter
=
{
template:
`<div>{{
count
}}</div>`,
computed:
{
count
()
{
return
store.state.count
}
}
}
每當store.state.count變化的時候,都會重新求取計算屬性,并且觸發(fā)更新相關聯(lián)的DOM。然而,這種模式導致組件依賴全局狀態(tài)單例。在模塊化的構建系統(tǒng)中,在每個需要使用state的組件中需要頻繁地導入,并且在測試組件時需要模擬狀態(tài)。15Vuex通過main.js文件中的createApp(App).use(store)為每一個子組件提供Store。部分代碼如下:import
{
createApp
}
from
'vue'
import
App
from
'./App.vue'
import
store
from
'./store'
createApp(App).use(store).mount('#app')
單個文件組件中通過computed()獲取狀態(tài)數(shù)據(jù)。代碼如下:<template><div>{{
count
}}</div></template>
<scriptsetup>import{computed}from'vue'import{useStore}from'vuex'conststore=useStore()
constcount=computed(()=>store.state.count
)</script>
【引入問題】
當一個組件需要獲取多個狀態(tài)的時候,將這些狀態(tài)都聲明為計算屬性會有些重復和冗余。怎么辦呢?【解決辦法】Vuex通過使用mapState()輔助函數(shù)幫助生成計算屬性,減少用戶按鍵的次數(shù)。2.在Vue組件中通過mapState()輔助函數(shù)獲得Vuex狀態(tài)。mapState()函數(shù)返回的是一個對象,用來獲取多個狀態(tài)。mapState()函數(shù)可以接受對象{}或數(shù)組[]作為參數(shù)。{}為鍵值對形式,key:value,key為計算屬性,value為函數(shù),參數(shù)為store.state,返回需要的state;當映射的計算屬性的名稱與state的子節(jié)點名稱相同時,可以給mapState傳一個字符串數(shù)組。9.3.3Vuex中state169.3.3Vuex中state//
1.在單獨構建的版本中輔助函數(shù)為
Vuex.mapState
computed:
mapState({
//
箭頭函數(shù)可使代碼更簡練
count:
state
=>
state.count,
//
傳字符串參數(shù)
'count'
等同于
`state
=>
state.count`
countAlias:
'count',
//
為了能夠使用
`this`
獲取局部狀態(tài),必須使用常規(guī)函數(shù)
countPlusLocalState
(state)
{
return
state.count
+
this.localCount
}
})
//
2.當映射的計算屬性的名稱與
state
的子節(jié)點名稱相同時
computed:
mapState([
//
映射
this.count
為
store.state.count
'count'
//可以有多個state對象中屬性(key),用逗號分隔])
【引入問題】如何將Vuex狀態(tài)與局部計算屬性混合使用呢?
【解決辦法】展開運算符(...)將多個對象合并為一個,再傳給computed屬性。
3.對象展開運算符部分代碼如下:computed:
{
localComputed
()
{
/*
...
*/
},
//
使用對象展開運算符將此對象混入到外部對象中
...mapState({
//
...
})
}
4.組件自有局部狀態(tài)
使用Vuex并不意味著需要將所有的狀態(tài)均放入Vuex。
如果有些狀態(tài)嚴格屬于單個組件,最好還是作為組件的局部狀態(tài)。可以根據(jù)具體應用開發(fā)需要進行權衡和確定。179.3.3Vuex中state
【例9-3】Vuex核心概念實戰(zhàn)--state的應用(項目vuex-state-1)
1.在當前目錄下,通過vuecreate命令創(chuàng)建項目,選擇babel+vuex+eslint+Vue3.x,完成后進入項目文件夾,啟動本地開發(fā)服務。命令如下,執(zhí)行結果如下圖所示。vuecreatevuex-state-1cdvuex-state-1npmrunserve2.在瀏覽器中打開http://localhost:8080,查看頁面。
3.看到下圖這個界面說明項目啟動成功,然后在項目的src目錄下新建一個目錄store,在該目錄下新建一個index.js文件,使用createStore({})創(chuàng)建store,并使用exportdefault導出store。具體代碼如下:import
{
createStore
}
from
'vuex'
export
default
createStore({
state:
{
bookname:
'Vue.js前端框架技術與實戰(zhàn)',
price:
69.80,
press:
'清華大學出版社'
},
getters:
{},
mutations:
{},
actions:
{},
modules:
{}
})
18【例9-3】Vuex核心概念實戰(zhàn)--state4.修改src/App.vue文件。文件包含template、script、style等3個部分,完成HelloWorld組件導入和使用。代碼如下:<template>
<div>
<img
alt="logo"
src="/logo.png"
/>
<HelloWorld
msg="歡迎使用清華社圖書"
/>
</div>
</template>
<script
setup>
import
HelloWorld
from
"./components/HelloWorld.vue";
</script>
<style>
#app
{text-align:
center;
color:
#2c3e50;
margin-top:
60px;}
</style>
5.修改components/HelloWorld.vue文件。代碼如下:<template>
<div
class="hello">
<h3>{{
msg
}}</h3>
<p>圖書名稱:{{
bookname1
}}</p>
<p>定價:{{
price1
}}</p>
<p>出版社:{{
press1
}}</p>
<h3>使用mapState()</h3>
<p>圖書名稱:{{
storeState.bookname}}</p>
<p>定價:{{
storeState.price
}}</p>
<p>出版社:{{
storeState.press
}}</p>
<!--
1-1.使用toRefs()獲取狀態(tài)
-->
<!--
<p>圖書名稱:{{
bookname}}</p>
<p>定價:{{
price
}}</p>
<p>出版社:{{
press
}}</p>
-->
</div>
</template>
<script
setup>
//
import
{
toRefs
}
from
'vue'
1-2.導入toRefs()
import
{
computed,
defineProps
}
from
'vue'
import
{
useStore,
mapState
}
from
'vuex'
defineProps({
msg:
String
})
const
store
=
useStore()
19【例9-3】Vuex核心概念實戰(zhàn)--state6.在src子文件夾下創(chuàng)建main.js。代碼如下:import
{
createApp
}
from
'vue'
import
App
from
'./App.vue'
import
store
from
'./store'
createApp(App).use(store).mount('#app')7.切換到瀏覽器界面,并刷新頁面,效果如下圖所示。
//
單個獲取store中的狀態(tài)數(shù)據(jù),使用計算函數(shù)
const
bookname1
=
computed(()
=>
store.state.bookname)
const
price1
=
computed(()
=>
store.state.price)
const
press1
=
computed(()
=>
store.state.press)
//
使用輔助函數(shù)一次性獲取所有狀態(tài)數(shù)據(jù),使用mapState()
const
storeStateFns
=
mapState(['bookname',
'price',
'press'])
//返回函數(shù)對象console.log(storeStateFns)
const
storeState
=
{}
//
對storeStateFns進行Object.keys(storeStateFns)=[bookname,price,press]
Object.keys(storeStateFns).forEach(fnkey
=>
{
const
fn
=
storeStateFns[fnkey].bind({
$store:
store
})
storeState[fnkey]
=
computed(fn)
})
//
const
{
bookname,
price,
press
}
=
toRefs(store.state)
1-3.使用toRefs()
</script>
<style
scoped>
h3
{margin:
5px
auto;}
</style>
209.3.4Vuex中getter1.Vuex中getter的需求背景【引入問題】工程項目中有時候需要從store.state中派生出一些狀態(tài),例如對列表進行過濾并計數(shù),可以使用計算屬性來實現(xiàn)。實現(xiàn)的代碼段如下:computed:{doneTodosCount(){//統(tǒng)計待辦項目中已經(jīng)完成的項目數(shù)returnthis.$store.state.todos.filter(todo
=>todo.done).length}}
如果有多個組件需要用到此屬性,要么復制這個函數(shù),要么抽取到一個共享函數(shù),然后在多處導入它,但無論哪種方式使用起來均不是很理想。【解決辦法】Vuex允許在store中定義getter(可以認為是store的計算屬性)。getter的返回值會根據(jù)它的依賴被緩存起來,且只有當它的依賴值發(fā)生了改變才會被重新計算。getter可以接受第為一個參數(shù)為state。部分代碼如下:import{createStore}from'vuex'const
store
=
createStore({
state:
{
todos:
[
{
id:
1,
text:
'...',
done:
true
},
{
id:
2,
text:
'...',
done:
false
}
]
},
getters:
{
doneTodos:
state
=>
{
return
state.todos.filter(todo
=>
todo.done)
}
}
})
212.getter使用方法。常用的方法有通過屬性、方法和mapGetters()輔助函數(shù)來訪問。
通過屬性訪問。getter會暴露為store.getters對象,可通過屬性的形式訪問這些值:store.getters.doneTodos//返回已完成項目[{id:1,text:'...',done:true}]getter可以接受將其他getter作為第二個參數(shù)。代碼如下:getters:
{
//
...
doneTodosCount:
(state,
getters)
=>
{
return
getters.doneTodos.length
}
}
//使用doneTodosCountstore.getters.doneTodosCount
//返回19.3.4Vuex中getter
在其它組件中可以很容易地使用它。代碼如下:constdoneTodosCount=computed(()=>store.getters.doneTodosCount)
注意:通過屬性訪問時,getter作為Vue的響應式系統(tǒng)的一部分緩存在其中。通過方法訪問。getters:
{
//
...
getTodoById:
(state)
=>
(id)
=>
{
return
state.todos.find(todo
=>
todo.id
===
id)
}
}
//使用方法
store.getters.getTodoById(2)
//
返回
{
id:
2,
text:
'...',
done:
false
}
229.3.4Vuex中getter在OptionsAPI編程中,通過mapGetters()輔助函數(shù)來訪問。代碼如下:import
{
mapGetters
}
from
'vuex'
export
default
{
//
...
computed:
{
//
使用對象展開運算符將
getter
混入
computed
對象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
//
...
])
}
}
如果想將一個getter屬性另取一個名字,使用對象形式來定義。代碼如下:mapGetters({
//
把
`this.doneCount`
映射為
`this.$store.getters.doneTodosCount`
doneCount:
'doneTodosCount'
})
【例9-4】Vuex核心概念實戰(zhàn)之二--getter的使用(項目vuex-getter-1)。步驟如下:1.在當前目錄下,新建vuex-getter-1項目,依次執(zhí)行下列指令,完成項目創(chuàng)建與配置工作。vuecreatevuex-getter-1cdvuex-getter-1npmrunserve
2.進入vuex-getter-1文件夾,刪除components/HelloWorld.vue組件,然后依次修改App.vue、src/store/index.js等文件。各文件具體內容如下:23【例9-4】Vuex核心概念實戰(zhàn)之二編輯main.js文件。import
{
createApp
}
from
'vue'
import
App
from
'./App.vue'
import
store
from
'./store'
createApp(App).use(store).mount('#app')
編輯index.js文件。import
{
createStore
}
from
'vuex'
export
default
createStore({
state:
{
bookname:
'Vue.js前端框架技術與實戰(zhàn)',
price:
69.8,
press:
'清華大學出版社',
total:
0.0,
count:
2
},
getters:
{
getPrice
(state)
{
return
state.price
},
getCount
(state)
{
return
state.count
},
getTotal
(state,
getters)
{
return
getters.getPrice
*
getters.getCount
}
},
mutations:
{},
actions:
{},
modules:
{}
})
編輯App.vue文件。<template>
<div>
<img
alt="Vue
logo"
src="/vuebook.jpg"
/>
<h3>{{
store.state.bookname
}}</h3>
<p>圖書定價:{{
getPrice
}}</p>
<p>圖書數(shù)量:{{
getCount
}}</p>
<p>購買總價:{{
getTotal
}}</p>
</div>
</template>
<scriptsetup>import{toRefs}from'vue'import{useStore}from'vuex'conststore=useStore()const{getPrice,getCount,getTotal}=toRefs(store.getters)</script>
<style>#app{
text-align:center;
color:#2c3e50;
margin-top:60px;}</style>3.切換到瀏覽器界面,刷新頁面,效果如圖9-11所示249.3.5Vuex中mutation
更改Vuex的store中的狀態(tài)的唯一方法是提交mutation(突變、變異、改變)。
Vuex中的mutation非常類似于事件:每個mutation都有一個字符串的事件類型(type)和一個回調函數(shù)(handler)-就是實際進行狀態(tài)更改的地方,并且它會接受state作為第一個參數(shù)。import{createStore}from'vuex'exportdefaultcreateStore({
state:
{
count:
1
},
mutations:
{
increment
(state)
{
//increment為事件類型type,state為參數(shù)
state.count++
//
變更狀態(tài)
}
}
})
用戶不能直接調用一個mutationhandler。這個選項更像是事件注冊:“當觸發(fā)一個類型為increment的mutation時,調用此函數(shù)”。要喚醒一個mutationhandler,需要以相應的type調用mit()方法。代碼如下:mit('increment')
提交載荷(payload)
可以向mit()傳入額外的參數(shù),即mutation的載荷。部分代碼如下://
...
mutations:
{
increment
(state,
n)
{
state.count
+=
n
}
}
259.3.5Vuex中mutation
喚醒這樣mutationhandler同樣需要以相應的type調用mit()方法。mit(type,[payload])//[]表示可選參數(shù)mit('increment',
10)
載荷應該是一個對象,這樣可以包含多個字段并且記錄的mutation會更易讀。部分代碼如下://
...
mit(type,[payload])//[]可選mit('increment',
10)
在多數(shù)情況下,載荷應該是一個對象,這樣可以包含多個字段并且記錄的mutation會更易讀。部分代碼如下:mutations:
{
increment
(state,
payload)
{
state.count
+=
payload.amount
//累加,payload是對象,amount是其一個屬性
}
}
相應的喚醒方法如下://把payload和type分開提交mit('increment',
{
amount:
10
})
對象風格的提交方式
提交mutation的另一種方式是直接使用包含
type
屬性的對象{}。//整個對象都作為載荷傳給mutation函數(shù)mit({
type:
'increment',
amount:
10
})
修改state對象的方法
有時會動態(tài)修改state對象,如增加對象的屬性,如何才能正確地實施呢?
可以修改state對象中的屬性方法如下:Vue.set(obj,'newProp',value)//Vue.set()方法
state.obj={...state.obj,newProp:value}//以新對象替換老對象269.3.5Vuex中mutation
例如,state對象中的student對象原來有name、sex兩個屬性,現(xiàn)在需要增加age屬性。正確的添加方法如下:import{createStore}from'vuex'exportdefaultcreateStore({
state:
{
student:
{
name:
'張?zhí)m英',
sex:
'女'
}
}
})
//以下給state添加一個age屬性
mutations:
{
addAge
(state)
{
Vue.set(state.student,
'age',
20)
//這是第一種方法,新增屬性需要使用引號
//
state.student
=
{
...state.student,
age:
18
}
//這是第二種方法
}
}
使用常量替代Mutation事件類型(選講)
在工程項目中,可以使用常量替代mutation事件類型。通常將這些常量放在單獨的文件中,可以讓項目中所包含的mutation一目了然,方便項目合作者查看使用。具體代碼如下:新建mutation-types.js文件//
mutation-types.js
export
const
SOME_MUTATION
=
'SOME_MUTATION'
27新建store.js文件//
store.js
import
{createStore}
from
'vuex'
import
{
SOME_MUTATION
}
from
'./mutation-types'
exportdefaultcreateStore({
state:
{
...
},
mutations:
{
//
使用
ES2015
風格的計算屬性命名功能來使用一個常量作為函數(shù)名
[SOME_MUTATION]
(state)
{
//
mutation
state
}
}
})
注意:函數(shù)名必須是帶[]的類型常量(如[SOME_MUTATION])。建議多人合作的大項目最好用常量的形式來處理mutation。小項目不需要這樣做。9.3.5Vuex中mutationmutation必須是同步函數(shù)
一條重要的原則就是要記住mutation必須是同步函數(shù)。為什么?要通過提交mutation的方式來改變狀態(tài)數(shù)據(jù),才能更明確地追蹤到狀態(tài)的變化。在組件中提交mutation
在OptionAPI編程模式下,組件中可以使用this.$mit(‘xxx')提交mutation,或者使用mapMutations輔助函數(shù)將組件中的methods映射為mit()調用(需要在根節(jié)點注入store)。具體實現(xiàn)的部分代碼如下:28組件中script標記中導入import
{
mapMutations
}
from
'vuex'
export
default
{
//
...
methods:
{
...mapMutations([
'increment',
//
將
`this.increment()`
映射為
`this.$mit('increment')`
//
`mapMutations`
也支持載荷:
'incrementBy'
//
將
`this.incrementBy(amount)`
映射為
`this.$mit('incrementBy',
amount)`
]),
...mapMutations({
add:
'increment'
//
將
`this.add()`
映射為
`this.$mit('increment')`
})
}
}
9.3.5Vuex中mutation299.3.5Vuex中mutation
在CompositionAPI編程模式下,組件的<script
setup>內可以在functionfunName()內使用mit("mutationName",[payload])來提交mutation。具體實現(xiàn)的部分代碼如下:<!--
采用Vue3.2
新增<script
setup>
-->
<script
setup>
import
{
useStore
}
from
'vuex';
const
store
=
useStore();
//狀態(tài)foods、total、orderSumfunction
add(n)
{
mit("addOrderAmount",
n);
mit("addTotal");
mit("totalSum");
}
function
reduce(n)
{
mit("reduceOrderAmount",
n);
mit("reduceTotal");
mit("totalSum");
}
</script>
309.3.6Vuex中action
action類似于mutation,又不同在于mutation。具體有以下兩點:action提交的是mutation,而不是直接變更狀態(tài)。action可以包含任意異步操作。
?actions對象里的方法需要使用store.dispatch調用。action函數(shù)接受一個與store實例具有相同方法和屬性的context對象,因此可以調用mit提交一個mutation,或者通過context.state和context.getters來獲取state和getters。
以下來注冊一個簡單的action。import{createStore}form'vuex'exportdefaultcreateStore({
state:
{
count:
0
},
mutations:
{
increment
(state)
{
state.count++
}
},
actions:
{
increment
(context)
{
mit('increment')
}
}
})
在項目實踐中,也可以使用ES2015的參數(shù)解構來簡化代碼(特別是需要多次調用commit時候)。簡化格式如下:
31actions:
{
increment
({commit
})
{
//{commit}相當于{commit:mit}
commit('increment')
//由原來mit簡化為commit
}
}
分發(fā)ActionAction通過store.dispatch方法觸發(fā)Mutations。代碼如下:store.dispatch('increment')
由于mutation必須同步執(zhí)行,但action就沒有這個約束。可以在action內部執(zhí)行異步操作。部分代碼如下:actions:
{
incrementAsync
({
commit
})
{
setTimeout(()
=>
{
//=>表示箭頭函數(shù)
commit('increment')
},
1000)
//1000毫秒后執(zhí)行
}
}
9.3.6Vuex中action329.3.6Vuex中actionActions支持同樣的載荷方式和對象方式進行分發(fā)://
以載荷形式分發(fā)
store.dispatch('incrementAsync',
{
amount:
10
})
//
以對象形式分發(fā)
store.dispatch({
type:
'incrementAsync',
amount:
10
})
在組件中分發(fā)Action
組件中使用this.$store.dispatch(‘xxx’)分發(fā)action,或者使用mapActions輔助函數(shù)將組件的methods映射為store.dispatch()調用(需要先在根節(jié)點注入store)。
在OptionsAPI編程模式下,Vue2.6.x中,組件中使用this.$store.dispatch(‘xxx')分發(fā)action,或者使用mapActions輔助函數(shù)將組件的methods映射為store.dispatch()調用(需要先在根節(jié)點注入store)。import
{
mapActions
}
from
'vuex'
export
default
{
//
...
methods:
{
...mapActions([
'increment',
//
將
`this.increment()`
映射為
`this.$store.dispatch('increment')`
//
`mapActions`
也支持載荷:
'incrementBy'
//
將
`this.incrementBy(amount)`
映射為
`this.$store.dispatch('incrementBy',
amount)`
]),
...mapActions({
add:
'increment'
//
將
`this.add()`
映射為
`this.$store.dispatch('increment')`
})
}
}
339.3.6Vuex中action(帶載荷)
在CompositionAPI編程模式下,組件的<scriptsetup>標記中可以在functionfunName()內使用dispatch("mutationName",[payload])來提交mutation。具體實現(xiàn)的部分代碼如下:<script
setup>
import
{useStore}
from
'vuex'
const
{state,commit,dispatch}
=
useStore()
const
add
=
()
=>
{
commit('increment')
}
const
asyncIncrement
=
()
=>
{
dispatch('incrementAsync',3)
}
</script>
Vuex核心概念實戰(zhàn)之三--muatations和actions的使用(項目vuex-mutation-action-1)。使用store的mutations和actions完成周薪調節(jié)功能。代碼如下,頁面效果如圖9-12~圖9-14所示。具體實現(xiàn)的步驟如下:1.在當前目錄下,新建vuex-3-mutation-action項目,依次執(zhí)行下列指令,完成項目創(chuàng)建與配置工作。vuecreatevuex-mutation-action-1cdvuex-mutation-action-1npmrunserve2.修改App.vue、src/store/index.js等文件,在components子文件夾下新建addWeeklyPay.vue、reduceWeek.vue兩個組件,刪除HelloWorld.vue組件。。349.3.6Vuex中action修改src/store/index.js文件。內容如下://
vuex-mutation-action-1
index.js
import
{
createStore
}
from
'vuex'
export
default
createStore({
state:
{
name:
'張成長',
weeklyPay:
5000,
week:
6
},
mutations:
{
add
(state)
{
state.weeklyPay
=
state.weeklyPay
+
100
},
addNum
(state,
num)
{
//
帶第二個參數(shù)num(幅度)
state.weeklyPay
=
state.weeklyPay
+
num
},
reduce
(state)
{
state.weeklyPay
=
state.weeklyPay
-
100
},
reduceNum
(state,
num)
{
//
帶第二個參數(shù)num(幅度)
state.weeklyPay
=
state.weeklyPay
-
num
}
},
修改App.vue文件。內容如下:<!--
vuex-mutation-action-1
App.vue
-->
<template>
<div
id="app">
<h2>使用mutation調增周薪</h2>
<add></add>
<hr
/>
<h2>使用action調減周薪</h2>
<reduce></reduce>
</div>
</template>
<script
setup>
import
add
from
'./components/addWeeklyPay.vue'
import
reduce
from
'./components/reduceWeeklyPay.vue'
</script>
<style
scoped>
#app
{
margin-top:
10px;
padding:
10px;
border:
1px
dashed
#112233;}
</style>
359.3.6Vuex中action編輯main.js文件import
{
createApp
}
from
'vue'
import
App
from
'./App.vue'
import
store
from
'./store'
createApp(App).use(store).mount('#app')
創(chuàng)建addWeeklyPay.vue組件<!--
addWeeklyPay.vue
-->
<template>
<div>
<p
v-once>
姓名:{{
$
}},第{{
$store.state.week
}}周,周薪:{{
$store.state.weeklyPay
}}元
</p>
<p>姓名:{{
name
}},第{{
week
}}周,周薪:{{
weeklyPay
}}元</p>
<button
@click="addWeeklyPay">增薪(100元)</button>
<button
@click="addWeeklyPayNum">增薪(Num元)</button>
</div>
</template>
actions:
{
addWeeklyPay
(context)
{
mit('add')
},
reduce
(context)
{
mit('reduce')
//
同步減少
},
reduceNum
(context,
num)
{
mit('reduceNum',
num)
//
同步減少
},
reduceAsync
(context)
{
setTimeout(()
=>
{
//
異步
mit('reduce')
},
1000)
},
reduceNumAsync
(context,
step)
{
//
異步帶參數(shù)
setTimeout(()
=>
{
mit('reduceNum',
step)
},
1000)
}
}
})
36<script
setup>
import
{
useStore
}
from
'vuex'
import
{
toRefs
}
from
'vue'
const
{
state,
commit
}
=
useStore()
//解構賦值const
addWeeklyPay
=
()
=>
{
commit('add')
}
const
addWeeklyPayNum
=
()
=>
{
commit('addNum',
150)
}
const
{
week,
name,
weeklyPay
}
=
toRefs(state)
//解構賦值</script>
<style
scoped="scoped">
button
{
border-radius:
4px
4px;
border:
1px
solid
#1f1202;
height:
28px;
background-color:
#F1F2F3;
}
</style>
創(chuàng)建reduceWeek.vue組件文件。內容如下:<!--
reduceWeek.vue
-->
<template>
<div>
<p
v-once>
姓名:{{
$
}},第{{
$store.state.week
}}周,
周薪:{{
$store.state.weeklyPay}}元
</p>
<p>姓名:{{
name
}},第{{
week
}}周,周薪:{{
weeklyPay
}}元</p>
<button
@click="reduceWeeklyPay">降薪(100元)</button>
<button
@click="reduceWeeklyPayNum">降薪(Num元)</button>
<button
@click="reduceAsync">異步Actions降薪(100元)</button>
<button
@click="reduceNumAsync(300)">異步Actions降薪(Num元)</button>
</div>
</template>
9.3.6Vuex中action37<style
scoped>
button
{
border:
1px
solid
#774477;
border-radius:
4px
4px;
height:
28px;
background-color:
#ebebeb;
}
</style>
3.刷新瀏覽器頁面,效果如圖9-12所示。兩個子組件中定義的按鈕樣式是略有差異。然后依次單擊各個組件中的各個按鈕,頁面效果如圖9-13所示。9.3.6Vuex中action<script
setup>
import
{
useStore
}
from
'vuex'
import
{
toRefs
}
from
'vue'
const
{
state,
dispatch
}
=
useStore()
const
{
name,
week,
weeklyPay
}
=
toRefs(state)
const
reduceWeeklyPay
=
()
=>
{
dispatch('reduce')
}
const
reduceWeeklyPayNum
=
()
=>
{
dispatch('reduceNum',
300)
}
const
reduceAsync
=
()
=>
{
dispatch('reduceAsync')
}
const
reduceNumAsync
=
(num)
=>
{
dispatch('reduceNumAsync',
num)
}
</script>
389.3.7Vuex中module
由于使用單一狀態(tài)樹,應用的所有狀態(tài)會集中在一個比較大的對象中。在工程應用變得非常復雜時,store對象就有可能變得相當臃腫。為了解決以上問題,Vuex允許將store分割成模塊(module)。每個模塊擁有自己的state、getter、mutation、action,甚至是嵌套子模塊--從上至下進行同樣方式的分割。多模塊定義方法。以下來定義兩個模塊,并注冊到Vuex中store中。部分代碼參考如下:const
module1
=
{
state:
{
...
},
mutations:
{
...
},
actions:
{
...
},
getters:
{
...
}
}
const
module2
=
{
state:
{
...
},
mutations:
{
...
},
actions:
{
...
}
}
exportdefaultcreateStore({
modules:
{
m1:
module1,
m2:
module2
}
})
store.state.m1//調用module1的狀態(tài)store.state.m2
//調用module2的狀態(tài)2.模塊的局部狀態(tài)及使用
對于模塊內部
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 行政積分制管理暫行辦法
- 西安市門頭牌匾管理暫行辦法
- 衡陽市重點水域管理辦法
- 西豐縣農(nóng)村環(huán)境管理辦法
- 觀山湖區(qū)停車場管理辦法
- 設備檢修后清理管理辦法
- 課件庫管理辦法心得體會
- 財政性資金指標管理辦法
- 貴州人口生育與管理辦法
- 貴州省露天煤礦管理辦法
- 江河治理與防洪工程課件
- 成都某污水處理廠施工組織設計
- 廣告制作交貨進度計劃及保障措施
- 網(wǎng)絡安全知識培訓資料
- 2025年下半年中小學教師資格考試題庫帶答案
- 2025年中職基礎會計試題
- 2025年江蘇省南京市中考道德與法治試卷(含解析)
- 同業(yè)培訓課件
- 中試平臺運營管理制度
- 2025至2030中國生物反饋儀行業(yè)產(chǎn)業(yè)運行態(tài)勢及投資規(guī)劃深度研究報告
- 【公開課】牛頓第二定律+課件+-2024-2025學年高一上學期物理人教版(2019)必修第一冊+
評論
0/150
提交評論