uniapp中vuex的應(yīng)用使用步驟
一、vuex是什么?
Vuex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。
按照自己理解來(lái)說(shuō)就是公共數(shù)據(jù)管理模塊。如果應(yīng)用中數(shù)據(jù)量比較大的可以應(yīng)用,不是很大的建議用緩存即可。
二、使用步驟
使用準(zhǔn)備在項(xiàng)目中新建store目錄,在該目錄下新建index.js文件
1.引入
由于uniapp中內(nèi)置了vuex,只需要規(guī)范引入即可:
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex);//vue的插件機(jī)制 //Vuex.Store 構(gòu)造器選項(xiàng) const store = new Vuex.Store({ state:{//存放狀態(tài) "username":"foo", "age":18 } }) export default store
// 頁(yè)面路徑:main.js import Vue from 'vue' import App from './App' import store from './store' Vue.prototype.$store = store App.mpType = 'app' // 把 store 對(duì)象提供給 “store” 選項(xiàng),這可以把 store 的實(shí)例注入所有的子組件 const app = new Vue({ store, ...App }) app.$mount()
2.state屬性,主要功能為存儲(chǔ)數(shù)據(jù)
第一種方法:通過(guò)屬性訪(fǎng)問(wèn),需要在根節(jié)點(diǎn)注入 store 。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <text>用戶(hù)名:{{username}}</text> </view> </template> <script> import store from '@/store/index.js';//需要引入store export default { data() { return {} }, computed: { username() { return store.state.username } } } </script>
第二種方法:在組件中使用,通過(guò) this.$store 訪(fǎng)問(wèn)到 state 里的數(shù)據(jù)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <text>用戶(hù)名:{{username}}</text> </view> </template> <script> export default { data() { return {} }, computed: { username() { return this.$store.state.username } } } </script>
進(jìn)階方法:通過(guò) mapState 輔助函數(shù)獲取。當(dāng)一個(gè)組件需要獲取多個(gè)狀態(tài)的時(shí)候,將這些狀態(tài)都聲明為計(jì)算屬性會(huì)有些重復(fù)和冗余。 為了解決這個(gè)問(wèn)題,我們可以使用 mapState 輔助函數(shù) 幫助我們生成計(jì)算屬性,讓你少按幾次鍵,(說(shuō)白了就是簡(jiǎn)寫(xiě),不用一個(gè)一個(gè)去聲明了,避免臃腫)
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>用戶(hù)名:{{username}}</view> <view>年齡:{{age}}</view> </view> </template> <script> import { mapState } from 'vuex'//引入mapState export default { data() { return {} }, computed: mapState({ // 從state中拿到數(shù)據(jù) 箭頭函數(shù)可使代碼更簡(jiǎn)練(就是簡(jiǎn)寫(xiě)) username: state => state.username, age: state => state.age, }) } </script>
3. Getter屬性,主要功能為計(jì)算篩選數(shù)據(jù)
可以認(rèn)為是 store 的計(jì)算屬性,對(duì) state 的加工,是派生出來(lái)的數(shù)據(jù)。 就像 computed 計(jì)算屬性一樣,getter 返回的值會(huì)根據(jù)它的依賴(lài)被緩存起來(lái),且只有當(dāng)它的依賴(lài)值發(fā)生改變才會(huì)被重新計(jì)算。(重點(diǎn),響應(yīng)式數(shù)據(jù)的應(yīng)用)
可以在多組件中共享 getter 函數(shù),這樣做還可以提高運(yùn)行效率。
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { todos: [{ id: 1, text: '我是內(nèi)容一', done: true }, { id: 2, text: '我是內(nèi)容二', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } }) export default store
Getter屬性接收傳遞參數(shù),主要為:state, 如果在模塊中定義則為模塊的局部狀態(tài)。getters, 等同于 store.getters。
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { todos: [{ id: 1, text: '我是內(nèi)容一', done: true }, { id: 2, text: '我是內(nèi)容二', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { //state :可以訪(fǎng)問(wèn)數(shù)據(jù) //getters:訪(fǎng)問(wèn)其他函數(shù),等同于 store.getters return getters.doneTodos.length }, getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } }) export default store
應(yīng)用Getter屬性方法一:通過(guò)屬性訪(fǎng)問(wèn),Getter 會(huì)暴露為 store.getters 對(duì)象,你可以以屬性的形式訪(fǎng)問(wèn)這些值。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view v-for="(item,index) in todos"> <view>{{item.id}}</view> <view>{{item.text}}</view> <view>{{item.done}}</view> </view> </view> </template> <script> import store from '@/store/index.js'//需要引入store export default { computed: { todos() { return store.getters.doneTodos } } } </script>
應(yīng)用Getter屬性方法二:通過(guò) this.$store 訪(fǎng)問(wèn)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view v-for="(item,index) in todos"> <view>{{item.id}}</view> <view>{{item.text}}</view> <view>{{item.done}}</view> </view> </view> </template> <script> export default { computed: { todos() { return this.$store.getters.doneTodos } } } </script>
應(yīng)用Getter屬性方法三:你也可以通過(guò)讓 getter 返回一個(gè)函數(shù),來(lái)實(shí)現(xiàn)給 getter 傳參。在你對(duì) store 里的數(shù)組進(jìn)行查詢(xún)時(shí)非常有用。注意,getter 在通過(guò)方法訪(fǎng)問(wèn)時(shí),每次都會(huì)去進(jìn)行調(diào)用,而不會(huì)緩存結(jié)果。(一次調(diào)用,一次請(qǐng)求,沒(méi)有依賴(lài)關(guān)系)
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view v-for="(item,index) in todos"> <view>{{item}}</view> </view> </view> </template> <script> export default { computed: { todos() { return this.$store.getters.getTodoById(2) } } } </script>
應(yīng)用Getter屬性方法進(jìn)階(簡(jiǎn)寫(xiě)):通過(guò) mapGetters 輔助函數(shù)訪(fǎng)問(wèn)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>{{doneTodosCount}}</view> </view> </template> <script> import {mapGetters} from 'vuex' //引入mapGetters export default { computed: { // 使用對(duì)象展開(kāi)運(yùn)算符將 getter 混入 computed 對(duì)象中 ...mapGetters([ 'doneTodos', 'doneTodosCount', // ... ]) } } </script>
4. Mutation屬性,Vuex中store數(shù)據(jù)改變的唯一地方(數(shù)據(jù)必須同步)
通俗的理解,mutations 里面裝著改變數(shù)據(jù)的方法集合,處理數(shù)據(jù)邏輯的方法全部放在 mutations 里,使數(shù)據(jù)和視圖分離。Vuex 中的 mutation 非常類(lèi)似于事件:每個(gè) mutation 都有一個(gè)字符串的事件類(lèi)型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler)。這個(gè)回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會(huì)接受 state 作為第一個(gè)參數(shù):
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1 }, mutations: { add(state) { // 變更狀態(tài) state.count += 2 } } }) export default store
你不能直接調(diào)用一個(gè) mutation handler。這個(gè)選項(xiàng)更像是事件注冊(cè):“當(dāng)觸發(fā)一個(gè)類(lèi)型為 add 的 mutation 時(shí),調(diào)用此函數(shù)”,要喚醒一個(gè) mutation handler,你需要以相應(yīng)的 type 調(diào)用 store.commit 方法。
注意:store.commit 調(diào)用 mutation(需要在根節(jié)點(diǎn)注入 store)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>數(shù)量:{{count}}</view> <button @click="addCount">增加</button> </view> </template> <script> import store from '@/store/index.js' export default { computed: { count() { return this.$store.state.count } }, methods: { addCount() { store.commit('add') } } } </script>
mutation中的函數(shù)接收參數(shù):你可以向 store.commit 傳入額外的參數(shù),即 mutation 的 載荷(payload):
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1 }, mutations: { //傳遞數(shù)值 add(state, n) { state.count += n } //傳遞對(duì)象類(lèi)型 add(state, payload) { state.count += payload.amount } } }) export default store
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>數(shù)量:{{count }}</view> <button @click="addCount">增加</button> </view> </template> <script> import store from '@/store/index.js' export default { computed: { count() { return this.$store.state.count } }, methods: { //傳遞數(shù)值 addCount() { store.commit('add', 5)//每次累加 5 } //傳遞對(duì)象 addCount () {//把載荷和type分開(kāi)提交 store.commit('add', { amount: 10 }) } } } </script>
應(yīng)用Getter屬性方法二:通過(guò) this.$store 訪(fǎng)問(wèn)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view v-for="(item,index) in todos"> <view>{{item.id}}</view> <view>{{item.text}}</view> <view>{{item.done}}</view> </view> </view> </template> <script> export default { computed: { todos() { return this.$store.getters.doneTodos } } } </script>
應(yīng)用mutation屬性方法進(jìn)階(簡(jiǎn)寫(xiě)):通過(guò) mapMutations輔助函數(shù)訪(fǎng)問(wèn)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>數(shù)量:{{count}}</view> <button @click="add">增加</button> </view> </template> <script> import { mapMutations } from 'vuex'//引入mapMutations export default { computed: { count() { return this.$store.state.count } }, methods: { ...mapMutations(['add'])//對(duì)象展開(kāi)運(yùn)算符直接拿到add } } </script>
5. Action屬性:
action 提交的是 mutation,通過(guò) mutation 來(lái)改變 state,而不是直接變更狀態(tài),action 可以包含任意異步操作。
// 頁(yè)面路徑:store/index.js // 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1 }, mutations:{ add(state) { // 變更狀態(tài) state.count += 2 } }, actions:{ addCountAction (context) { context.commit('add') } } }) export default store
action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對(duì)象,因此你可以調(diào)用 context.commit 提交一個(gè) mutation,或者通過(guò) context.state 和 context.getters 來(lái)獲取 state 和 getters。
actions 通過(guò) store.dispatch 方法觸發(fā):
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>數(shù)量:{{count}}</view> <button @click="add">增加</button> </view> </template> <script> import store from '@/store/index.js'; export default { computed: { count() { return this.$store.state.count } }, methods: { add () { store.dispatch('addCountAction') } } } </script>
actions 支持以載荷形式分發(fā):
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1 }, mutations:{ add(state, payload) { state.count += payload.amount } }, actions:{ addCountAction (context , payload) { context.commit('add',payload) } } }) export default store
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>數(shù)量:{{count }}</view> <button @click="add">增加</button> </view> </template> <script> import store from '@/store/index.js'; export default { computed: { count() { return this.$store.state.count } }, methods: { add () { // 以載荷形式分發(fā) store.dispatch('addCountAction', {amount: 10}) } add () { // 以對(duì)象形式分發(fā) store.dispatch({ type: 'addCountAction', amount: 5 }) } } } </script>
actions的異步:
// 頁(yè)面路徑:store/index.js //調(diào)用mutations的方法來(lái)改變數(shù)據(jù)(同步、異步) actions:{ //異步調(diào)用 actionA({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('add',5) resolve() }, 2000) }) } actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => {commit('someOtherMutation') }) async actionA ({ commit }) {commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } } }
應(yīng)用Actions屬性方法進(jìn)階(簡(jiǎn)寫(xiě)):通過(guò) mapActions輔助函數(shù)訪(fǎng)問(wèn)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view> <view>數(shù)量:{{count }}</view> <button @click="addCountAction">增加</button> </view> </template> <script> import { mapActions } from 'vuex' export default { computed: { count() { return this.$store.state.count } }, methods: { ...mapActions([ 'addCountAction', // 將 `this.addCountAction()` 映射為 `this.$store.dispatch('addCountAction')` ]) } } </script>
6. Module結(jié)構(gòu)。
由于使用單一狀態(tài)樹(shù),應(yīng)用的所有狀態(tài)會(huì)集中到一個(gè)比較大的對(duì)象。當(dāng)應(yīng)用變得非常復(fù)雜時(shí),store 對(duì)象就有可能變得相當(dāng)臃腫。為了解決以上問(wèn)題,Vuex 允許我們將 store 分割成模塊(module)。每個(gè)模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進(jìn)行同樣方式的分割:
1.在 store 文件夾下新建 modules 文件夾,并在下面新建 moduleA.js 和 moduleB.js 文件用來(lái)存放 vuex 的 modules 模塊。
├── components # 組件文件夾
└── myButton
└── myButton.vue # myButton組件
├── pages
└── index
└── index.vue # index頁(yè)面
├── static
├── store
├── index.js # 我們組裝模塊并導(dǎo)出 store 的地方
└── modules # 模塊文件夾
├── moduleA.js # 模塊moduleA
└── moduleB.js # 模塊moduleB
├── App.vue
├── main.js
├── manifest.json
├── pages.json
└── uni.scss
2.在 main.js 文件中引入 store。
// 頁(yè)面路徑:main.js import Vue from 'vue' import App from './App' import store from './store' Vue.prototype.$store = store // 把 store 對(duì)象提供給 “store” 選項(xiàng),這可以把 store 的實(shí)例注入所有的子組件 const app = new Vue({ store, ...App }) app.$mount()
3.在項(xiàng)目根目錄下,新建 store 文件夾,并在下面新建 index.js 文件,作為模塊入口,引入各子模塊。
// 頁(yè)面路徑:store/index.js import Vue from 'vue' import Vuex from 'vuex' import moduleA from '@/store/modules/moduleA' import moduleB from '@/store/modules/moduleB' Vue.use(Vuex) export default new Vuex.Store({ modules:{ moduleA,moduleB } })
4.子模塊 moduleA 頁(yè)面內(nèi)容。
// 子模塊moduleA路徑:store/modules/moduleA.js export default { state: { text:"我是moduleA模塊下state.text的值" }, getters: { }, mutations: { }, actions: { } }
5.子模塊 moduleB 頁(yè)面內(nèi)容。
// 子模塊moduleB路徑:store/modules/moduleB.js export default { state: { timestamp: 1608820295//初始時(shí)間戳 }, getters: { timeString(state) {//時(shí)間戳轉(zhuǎn)換后的時(shí)間 var date = new Date(state.timestamp); var year = date.getFullYear(); var mon = date.getMonth()+1; var day = date.getDate(); var hours = date.getHours(); var minu = date.getMinutes(); var sec = date.getSeconds(); var trMon = mon<10 ? '0'+mon : mon var trDay = day<10 ? '0'+day : day return year+'-'+trMon+'-'+trDay+" "+hours+":"+minu+":"+sec; } }, mutations: { updateTime(state){//更新當(dāng)前時(shí)間戳 state.timestamp = Date.now() } }, actions: { } }
6.在頁(yè)面中引用組件 myButton ,并通過(guò) mapState 讀取 state 中的初始數(shù)據(jù)。
<!-- 頁(yè)面路徑:pages/index/index.vue --> <template> <view class="content"> <view>{{text}}</view> <view>時(shí)間戳:{{timestamp}}</view> <view>當(dāng)前時(shí)間:{{timeString}}</view> <myButton></myButton> </view> </template> <script> import {mapState,mapGetters} from 'vuex' export default { computed: { ...mapState({ text: state => state.moduleA.text, timestamp: state => state.moduleB.timestamp }), ...mapGetters([ 'timeString' ]) } } </script>
7.在組件 myButton中,通過(guò) mutations 操作刷新當(dāng)前時(shí)間。
<!-- 組件路徑:components/myButton/myButton.vue --> <template> <view> <button type="default" @click="updateTime">刷新當(dāng)前時(shí)間</button> </view> </template> <script> import {mapMutations} from 'vuex' export default { data() { return {} }, methods: { ...mapMutations(['updateTime']) } } </script>
總結(jié)
vue是單向數(shù)據(jù)流,子組件不能直接修改父組件的數(shù)據(jù),而通過(guò)vuex狀態(tài)管理實(shí)現(xiàn):把組件的共享狀態(tài)抽取出來(lái),以一個(gè)全局單例模式管理。在這種模式下,我們的組件樹(shù)構(gòu)成了一個(gè)巨大的“視圖”,不管在樹(shù)的哪個(gè)位置,任何組件都能獲取狀態(tài)或者觸發(fā)行為!
vuex的整體結(jié)構(gòu)并不復(fù)雜,知識(shí)規(guī)范比較繁瑣,自己多試幾遍就好了。
到此這篇關(guān)于uniapp中vuex應(yīng)用使用的文章就介紹到這了,更多相關(guān)uniapp中vuex應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于JavaScript實(shí)現(xiàn)圖片點(diǎn)擊彈出窗口而不是保存
這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)圖片點(diǎn)擊彈出窗口而不是保存的相關(guān)資料,需要的朋友可以參考下2016-02-02js實(shí)現(xiàn)省級(jí)聯(lián)動(dòng)(數(shù)據(jù)結(jié)構(gòu)優(yōu)化)
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)省級(jí)聯(lián)動(dòng),數(shù)據(jù)結(jié)構(gòu)優(yōu)化,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07詳解webpack3如何正確引用并使用jQuery庫(kù)
本篇文章主要介紹了詳解webpack3如何正確引用并使用jQuery庫(kù),具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08在線(xiàn)編輯器中換行與內(nèi)容自動(dòng)提取
這幾天在寫(xiě)在線(xiàn)編輯器,碰到個(gè)問(wèn)題,當(dāng)使用回車(chē)換行時(shí)不是你希望的<br>而是<p></p>對(duì)或是<div></div>對(duì)。使用google搜索,在網(wǎng)上找不到滿(mǎn)意的答案。2009-04-04javascript解決小數(shù)的加減乘除精度丟失的方案
這篇文章主要介紹了javascript解決小數(shù)的加減乘除精度丟失的方案的相關(guān)資料以及JavaScript中關(guān)于丟失數(shù)字精度的問(wèn)題的探討,非常的詳細(xì),需要的朋友可以參考下2016-05-05動(dòng)態(tài)JavaScript所造成一些你不知道的危害
這篇文章給大家整理了動(dòng)態(tài)JavaScript所造成的一些大家可能不知道的危害,文章介紹的很詳細(xì),有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-09-09JS實(shí)現(xiàn)超簡(jiǎn)單的鼠標(biāo)拖動(dòng)效果
這篇文章主要介紹了JS實(shí)現(xiàn)超簡(jiǎn)單的鼠標(biāo)拖動(dòng)效果,涉及JavaScript響應(yīng)鼠標(biāo)事件動(dòng)態(tài)操作頁(yè)面元素的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11