習(xí)慣養(yǎng)成很容易谓晌,戒掉卻很難!2系印筐赔!
什么是Vuex?
Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式钻趋。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)川陆。
Vuex解決了什么問題剂习?
解決兩個(gè)問題
多個(gè)組件依賴于同一狀態(tài)時(shí)蛮位,對(duì)于多層嵌套的組件的傳參將會(huì)非常繁瑣,并且對(duì)于兄弟組件間的狀態(tài)傳遞無能為力鳞绕。
來自不同組件的行為需要變更同一狀態(tài)失仁。以往采用父子組件直接引用或者通過事件來變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱们何,通常會(huì)導(dǎo)致無法維護(hù)的代碼萄焦。
什么時(shí)候用Vuex?
當(dāng)項(xiàng)目遇到以下兩種場景時(shí)
多個(gè)組件依賴于同一狀態(tài)時(shí)冤竹。
來自不同組件的行為需要變更同一狀態(tài)拂封。
Vuex的5個(gè)核心屬性是什么?
分別是 state鹦蠕、getter冒签、mutation、action钟病、module 萧恕。
Vuex中狀態(tài)儲(chǔ)存在哪里,怎么改變它肠阱?
存儲(chǔ)在state中票唆,改變Vuex中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。
Vuex中狀態(tài)是對(duì)象屹徘,使用時(shí)候注意什么走趋?
因?yàn)閷?duì)象是引用類型,復(fù)制后改變屬性還是會(huì)影響原始數(shù)據(jù)噪伊,這樣會(huì)改變state里面的狀態(tài)簿煌,是不允許典挑,所以先用深度克隆復(fù)制對(duì)象,再修改啦吧。
怎么在組件中批量使用Vuex的state狀態(tài)您觉?
使用mapState輔助函數(shù), 利用對(duì)象展開運(yùn)算符將state混入computed對(duì)象中
import {mapState} from 'vuex'
export default{
????computed:{
????????...mapState(['price','number'])
????}
}
Vuex中要從state派生一些狀態(tài)出來,且多個(gè)組件使用它授滓,該怎么做琳水?
使用getter屬性,相當(dāng)Vue中的計(jì)算屬性computed般堆,只有原狀態(tài)改變派生狀態(tài)才會(huì)改變在孝。
getter接收兩個(gè)參數(shù),第一個(gè)是state淮摔,第二個(gè)是getters(可以用來訪問其他getter)私沮。
const store = newVuex.Store({
????state: {
????????price: 10,
????????number: 10,
????????discount: 0.7,
????},
????getters: {
????????total: state => {
????????????return state.price * state.number
????????},
????????discountTotal: (state, getters) => {
????????????return state.discount * getters.total
????????}
????},
});
然后在組件中可以用計(jì)算屬性computed通過this.$store.getters.total這樣來訪問這些派生轉(zhuǎn)態(tài)。
computed: {
????total() {
????????return this.$store.getters.total
????},
????discountTotal() {
????????return this.$store.getters.discountTotal
????}
}
怎么通過getter來實(shí)現(xiàn)在組件內(nèi)可以通過特定條件來獲取state的狀態(tài)和橙?
通過讓getter返回一個(gè)函數(shù)仔燕,來實(shí)現(xiàn)給getter傳參。然后通過參數(shù)來進(jìn)行判斷從而獲取state中滿足要求的狀態(tài)魔招。
const store = new Vuex.Store({
????state: {
????????todos: [
????????????{ id: 1, text: '...', done: true},
????????????{ id: 2, text: '...', done: false}
????????]
????},
????getters: {
????????getTodoById: (state) => (id) =>{
????????????return state.todos.find(todo => todo.id === id)
????????}
????},
});
然后在組件中可以用計(jì)算屬性computed通過this.$store.getters.getTodoById(2)這樣來訪問這些派生轉(zhuǎn)態(tài)晰搀。
computed: {
????getTodoById() {
????????return this.$store.getters.getTodoById
????},
}
mounted(){
????console.log(this.getTodoById(2).done)//false
}
怎么在組件中批量使用Vuex的getter屬性
使用mapGetters輔助函數(shù), 利用對(duì)象展開運(yùn)算符將getter混入computed 對(duì)象中
import {mapGetters} from 'vuex'
export default{
????computed:{
????????...mapGetters(['total','discountTotal'])
????}
}
怎么在組件中批量給Vuex的getter屬性取別名并使用
使用mapGetters輔助函數(shù), 利用對(duì)象展開運(yùn)算符將getter混入computed 對(duì)象中
import {mapGetters} from 'vuex'
export default{
????computed:{
????????...mapGetters(
????????????myTotal:'total',
????????????myDiscountTotal:'discountTotal',
????????)
????}
}
在Vuex的state中有個(gè)狀態(tài)number表示貨物數(shù)量,在組件怎么改變它办斑。
首先要在mutations中注冊一個(gè)mutation
const store = new Vuex.Store({
????state: {
????????number: 10,
????},
????mutations: {
????????SET_NUMBER(state,data){
????????????state.number=data;
????????}
????},
});
在組件中使用this.$store.commit提交mutation外恕,改變number
this.$store.commit('SET_NUMBER',10)
在Vuex中使用mutation要注意什么。
mutation 必須是同步函數(shù)
在組件中多次提交同一個(gè)mutation乡翅,怎么寫使用更方便鳞疲。
使用mapMutations輔助函數(shù),在組件中這么使用
methods:{
????...mapMutations({
????????setNumber:'SET_NUMBER',
????})
}
然后調(diào)用this.setNumber(10)相當(dāng)調(diào)用this.$store.commit('SET_NUMBER',10)
Vuex中action和mutation有什么區(qū)別?
action 提交的是 mutation蠕蚜,而不是直接變更狀態(tài)尚洽。mutation可以直接變更狀態(tài)。
action 可以包含任意異步操作波势。mutation只能是同步操作翎朱。
提交方式不同,action 是用this.$store.dispatch('ACTION_NAME',data)來提交尺铣。mutation是用this.$store.commit('SET_NUMBER',10)來提交拴曲。
接收參數(shù)不同,mutation第一個(gè)參數(shù)是state凛忿,而action第一個(gè)參數(shù)是context澈灼,其包含了
{
????state,????? // 等同于 `store.state`,若在模塊中則為局部狀態(tài)
????rootState,? // 等同于 `store.state`,只存在于模塊中
????commit,???? // 等同于 `store.commit`
????dispatch,?? // 等同于 `store.dispatch`
????getters,??? // 等同于 `store.getters`
????rootGetters // 等同于 `store.getters`叁熔,只存在于模塊中
}
Vuex中action和mutation有什么相同點(diǎn)委乌?
??? 第二參數(shù)都可以接收外部提交時(shí)傳來的參數(shù)。
this.$store.dispatch('ACTION_NAME',data)和this.$store.commit('SET_NUMBER',10)
在組件中多次提交同一個(gè)action荣回,怎么寫使用更方便遭贸。
使用mapActions輔助函數(shù),在組件中這么使用
methods:{
????...mapActions({
????????setNumber:'SET_NUMBER',
????})
}
然后調(diào)用this.setNumber(10)相當(dāng)調(diào)用this.$store.dispatch('SET_NUMBER',10)
Vuex中action通常是異步的,那么如何知道action什么時(shí)候結(jié)束呢心软?
在action函數(shù)中返回Promise壕吹,然后再提交時(shí)候用then處理
actions:{
????SET_NUMBER_A({commit},data){
????????return newPromise((resolve,reject) =>{
????????????setTimeout(() =>{
????????????????commit('SET_NUMBER',10)
????????????},2000)
????????}
????????)
????}
}
this.$store.dispatch('SET_NUMBER_A').then(() => {
??// ...
})
Vuex中有兩個(gè)action,分別是actionA和actionB删铃,其內(nèi)都是異步操作耳贬,在actionB要提交actionA,需在actionA處理結(jié)束再處理其它操作猎唁,怎么實(shí)現(xiàn)咒劲?
利用ES6的async和await來實(shí)現(xiàn)。
actions:{
????async actionA({commit}){
????????//...
????},
????async actionB({dispatch}){
????????await dispatch ('actionA')//等待actionA完成
????????// ...
????}
}
有用過Vuex模塊嗎诫隅,為什么要使用腐魂,怎么使用。
有阎肝,因?yàn)槭褂脝我粻顟B(tài)樹挤渔,應(yīng)用的所有狀態(tài)會(huì)集中到一個(gè)比較大的對(duì)象。當(dāng)應(yīng)用變得非常復(fù)雜時(shí)风题,store 對(duì)象就有可能變得相當(dāng)臃腫。所以將 store 分割成模塊(module)嫉父。每個(gè)模塊擁有自己的 state沛硅、mutations、actions绕辖、getters摇肌,甚至是嵌套子模塊,從上至下進(jìn)行同樣方式的分割仪际。
在module文件新建moduleA.js和moduleB.js文件围小。在文件中寫入
const state={
????//...
}
const getters={
????//...
}
const mutations={
????//...
}
const actions={
????//...
}
export default{
????state,
????getters,
????mutations,
????actions
}
然后再index.js引入模塊
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import moduleA from './module/moduleA'
import moduleB from './module/moduleB'
const store = newVuex.Store({
????modules:{
????????moduleA,
????????moduleB
????}
})
export default store
在模塊中,getter和mutation接收的第一個(gè)參數(shù)state树碱,是全局的還是模塊的肯适?
第一個(gè)參數(shù)state是模塊的state,也就是局部的state成榜。
在模塊中框舔,getter和mutation和action中怎么訪問全局的state和getter
在getter中可以通過第三個(gè)參數(shù)rootState訪問到全局的state,可以通過第四個(gè)參數(shù)rootGetters訪問到全局的getter。
在mutation中不可以訪問全局的satat和getter,只能訪問到局部的state刘绣。
在action中第一個(gè)參數(shù)context中的context.rootState訪問到全局的state樱溉,context.rootGetters訪問到全局的getter。
在組件中怎么訪問Vuex模塊中的getter和state,怎么提交mutation和action纬凤?
直接通過this.$store.getters和this.$store.state來訪問模塊中的getter和state福贞。
直接通過this.$store.commit('mutationA',data)提交模塊中的mutation。
直接通過this.$store.dispatch('actionA,data')提交模塊中的action停士。
用過Vuex模塊的命名空間嗎肚医?為什么使用,怎么使用向瓷。
??? 默認(rèn)情況下肠套,模塊內(nèi)部的action、mutation和getter是注冊在全局命名空間猖任,如果多個(gè)模塊中action你稚、mutation的命名是一樣的,那么提交mutation朱躺、action時(shí)刁赖,將會(huì)觸發(fā)所有模塊中命名相同的mutation、action长搀。
這樣有太多的耦合宇弛,如果要使你的模塊具有更高的封裝度和復(fù)用性,你可以通過添加namespaced: true 的方式使其成為帶命名空間的模塊源请。
export default{
????namespaced: true,
????state,
????getters,
????mutations,
????actions
}
怎么在帶命名空間的模塊內(nèi)提交全局的mutation和action枪芒?
??? 將 { root: true } 作為第三參數(shù)傳給 dispatch 或 commit 即可。
this.$store.dispatch('actionA', null, { root: true})
this.$store.commit('mutationA', null, { root: true})
怎么在帶命名空間的模塊內(nèi)注冊全局的action谁尸?
actions: {
????actionA: {
????????root: true,
????????handler (context, data) { ... }
????}
??}
組件中怎么提交modules中的moduleA中的mutationA舅踪?
this.$store.commit('moduleA/mutationA',data)
怎么使用mapState,mapGetters良蛮,mapActions和mapMutations這些函數(shù)來綁定帶命名空間的模塊抽碌?
首先使用createNamespacedHelpers創(chuàng)建基于某個(gè)命名空間輔助函數(shù)
import { createNamespacedHelpers } from 'vuex';
const { mapState, mapActions } = createNamespacedHelpers('moduleA');
export default{
????computed: {
????????// 在 `module/moduleA` 中查找
????????...mapState({
????????????a: state => state.a,
????????????b: state => state.b
????????})
????},
????methods: {
????????// 在 `module/moduleA` 中查找
????????...mapActions([
????????????'actionA',
????????????'actionB'
????????])
????}
}
Vuex插件有用過嗎?怎么用簡單介紹一下决瞳?
Vuex插件就是一個(gè)函數(shù)货徙,它接收 store 作為唯一參數(shù)。在Vuex.Store構(gòu)造器選項(xiàng)plugins引入皮胡。
在store/plugin.js文件中寫入
export default function createPlugin(param){
????returnstore =>{
????????//...
????}
}
然后在store/index.js文件中寫入
import createPlugin from './plugin.js'
const plugin = createPlugin()
const store = newVuex.Store({
??// ...
??plugins: [myPlugin]
})
在Vuex插件中怎么監(jiān)聽組件中提交mutation和action痴颊?
用Vuex.Store的實(shí)例方法subscribe監(jiān)聽組件中提交mutation
用Vuex.Store的實(shí)例方法subscribeAction監(jiān)聽組件中提交action
在store/plugin.js文件中寫入
export default function createPlugin(param) {
????returnstore => {
????????store.subscribe((mutation, state) => {
????????????console.log(mutation.type)//是那個(gè)mutation
????????????console.log(mutation.payload)
????????????console.log(state)
????????})
????????// store.subscribeAction((action, state) => {
????????//???? console.log(action.type)//是那個(gè)action
????????//???? console.log(action.payload)//提交action的參數(shù)
????????// })
????????store.subscribeAction({
????????????before: (action, state) => {//提交action之前
????????????????console.log(`before action ${action.type}`)
????????????},
????????????after: (action, state) => {//提交action之后
????????????????console.log(`after action ${action.type}`)
????????????}
????????})
????}
}
然后在store/index.js文件中寫入
import createPlugin from './plugin.js'
const plugin = createPlugin()
const store = newVuex.Store({
??// ...
??plugins: [myPlugin]
})
在v-model上怎么用Vuex中state的值?
需要通過computed計(jì)算屬性來轉(zhuǎn)換胸囱。
<input v-model="message">
// ...
computed: {
????message: {
????????get () {
????????????return this.$store.state.message
????????},
????????set (value) {
????????????this.$store.commit('updateMessage', value)
????????}
????}
}