vuex知識筆記,及與localStorage和sessionStorage的區別

来源:https://www.cnblogs.com/tandaxia/archive/2020/02/23/12353218.html
-Advertisement-
Play Games

Vuex和localStorage、sesstionStorage的區別,應用場景。vuex的State、Getter、Mutation、Action、Module等技術知識點掌握。 ...


菜單快捷導航

  1. Vuex是什麼東東,有什麼應用場景?localStorage和sessionStorage能否替代它?
  2. Vuex知識點State、Getter、Mutaion、Action
  3. Vuex模塊化(Module)

 1、Vuex概念和應用場景

  首先,Vuex是什麼,官網介紹說Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。我的理解就是Vuex就是類似於sessionStorage這樣管理數據(本地存和取)的一種技術方案。

  既然vuex類似於sessionStorage,那為何我們還要學習vuex,直接用sessionStorage和localStorage不就好了?這個問得好,我來描述一種場景:多個視圖(view)組件都要用到某一條數據(狀態),當這條數據發生變化的時候,依賴於該數據(狀態)的相關視圖(view)都要跟著即時更新。這種場景在工作中非常常見,我說一個自己碰到的例子,以前有一個react項目,其中有個功能是在pc頁面自定義小程式頁面,然後整個PC頁面有三個組件組成,在三個組件中還有其他的很多子組件。然後一開始的做法就是通過事件和組件間傳值來進行整個頁面數據同步更新,後面隨著組件越來越多,功能越來越複雜,麻煩和問題也就越來越多。然後每一個後面來接手的同事看代碼都要看好一陣,長痛不如短痛...

  對的,在工作中這種常見的多個組件依賴於同一條數據(狀態),需要即時響應更新的情況,vuex的價值就體現出來了。這種情況下,vuex相比其他實現手段,就要簡單干脆方便多了!先看一個小例子,看看vuex和localStorage、sessionStorage的區別,上圖:

  如圖,vuexPageA頁面中引用了三個組件,每個組件都分別從localStorage、sessionStorage、vuex中取了一個值。點擊按鈕加1的時候,vuex的值是及時更新了,其他需要刷新才能更新。總結一下:

  • localStorage存儲的值能夠永久的存儲在瀏覽器上。不管是重新打開新視窗還是重啟,同一個瀏覽器上的相同功能變數名稱下,localStorage的值一直在。
  • sessionStorage存儲的值依賴於當前視窗(當前會話), 只要當前視窗不關閉,它存儲的數據就一直在。一旦關閉視窗或者打開新視窗,sessionStorage之前存儲的數據就會消失。
  • 相比localStorage和sessionStorage,vuex存儲的數據可以即時更新到,當前項目下的所有引用了該數據的組件。但是如果刷新頁面的話,vuex存儲的值會重置,而localStorage和sessionStorage存儲的值不會重置。

  相關代碼見:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageA.vue

 

2、Vuex知識點State、Getter、Mutaion、Action

2.1 Vuex之State和mapState

  每一個Vuex應用的核心就是store(倉庫),“store"基本上就是一個容器。Vuex使用單一狀態樹,相當於用一個對象(store)就包含了全部的應用層級狀態,也就是說每個應用也只包含一個store實例。因此Vuex的使用從new一個Vuex.Store實例(store實例)開始。store實例中的State屬性就是用來存放Vue應用的所有的狀態。先來看要給最簡單的包含State屬性的store實例:

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0,
    },
})

後面的mutations、getters、actions再慢慢往裡面加入代碼。

  store實例創建,如何應用?Vue實例創建時,提供了一個store選項,可以讓Vuex通過store選項,將store實例對象從根組件”註入“到每一個子組件中:

import Vue from 'vue'
import App from './App.vue'
import router from './router.js'

//vuex 之 store實例對象
import store from './api/store/index' 

new Vue({
  router,  
  store, // 把 store 對象提供給 “store” 選項,這可以把 store 的實例註入所有的子組件
  render: h => h(App)
}).$mount('#app')

  store實例註入根組件後,應用中的每個組件中通過this.$store指的就是該store實例對象。那麼現在如何在Vue組件中展示store中的state狀態(數據)呢?由於Vuex的狀態存儲是即時響應的,從store實例中讀取狀態最簡單的方法就是在Vue組件中”計算屬性“computed中返回某個狀態。每當store.state中某個狀態變化的時候,都會重新求取計算屬性,並且觸發更新相關聯的DOM。

  mapState是一個輔助函數,當我們應用中一個組件需要獲取store中多個狀態的時候,使用mapState輔助函數可以幫助我們更加方便生成計算屬性。看看下麵的應用測試代碼:

import { mapState } from 'vuex';

    export default {
        data(){
            return {
                localCount: 88
            }
        },
        mounted(){
            console.log("...store對象:", this.$store);
        },
        computed:{
            localStorage_count(){
                return localStorage.getItem('localStorage_count')
            },
            //使用對象展開符"...",可以將對象目標對象混入到外部對象中
            ...mapState({
                sessionStorage_count(){
                    return sessionStorage.getItem('sessionStorage_count')
                },
                vuex_count: state => state.count, //箭頭函數可以使代碼更簡練
                vuex_count_alias: 'count', //傳字元串參數'count'等同於 state => state.count
                // 為了能夠使用 `this` 獲取局部狀態,必須使用常規函數
                countPlusLocalState (state) {
                    return state.count + this.localCount
                }
            }),
        },
    }
View Code

 

2.2 Vuex之Getter和mapGetters

  有時我們需要從store中的state種派生出一些狀態,比如對store中的某一個狀態(數據)進行篩選過濾,然後特別是當有多個組件需要用到這種狀態(數據)時,“getter"就出場了!Vuex允許我們在store中定義”getter"(可以認為是store對象的計算屬性)。就像計算屬性一樣,getter的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。Getter接受state作為其第一個參數:

export default new Vuex.Store({
    state: {
        count: 0,
        todos: [
            { id: 1, text: '金戈鐵馬,氣吞萬里如虎', done: true },
            { id: 2, text: '老驥伏櫪,志在千里', done: false },
            { id: 3, text: '周公吐哺,天下歸心', done: true },
            { id: 4, text: '但使龍城飛將在,不教胡馬度陰山', done: false },
        ]
    },
    //Vuex允許我們再store中定義"getter"(可以認為是store的計算屬性)。
    // 就像計算屬性一樣,getter的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。
    getters: {
        doneTodos: state => {
            console.log('...state.getters.donwTodos...')
            return state.todos.filter(todo => todo.done)
        },
        //Getter也可以接受其他getter作為第二個參數
        //getter在通過屬性訪問時是作為Vue的響應式系統的一部分緩存其中的
        doneTodosCount: (state, getters) => {
            console.log('...state.getters.doneTodosLength...', getters.doneTodos)
            return getters.doneTodos.length;
        },
        //通過方法訪問:通過讓getter返回一個函數,來實現給getter傳參。
        //getter在通過方法訪問時,每次都會去進行調用,而不會緩存結果。
        getTodoById: (state) => (id) => {
            console.log('...state.getters.getTodoById...: ', id);
            return state.todos.find(todo => todo.id === id);
        }
    },
    
})
View Code

   Getter應用:Getter會暴露為 store.getters 對象,然後在組件中,我們可以通過this.$store.getters來得到getter。getter裡面的屬性,可以返回屬性,也可以返回方法。如果getter通過屬性訪問時是作為Vue的響應式系統的一部分緩存,首次調用後再次調用時就會調用緩存,只有該屬性的依賴值變化時,再次調用該屬性才會重新調用重新緩存。如果getter通過方法訪問時,每次都會去進行調用,而不會緩存結果。組件中應用測試代碼:

methods:{
            //state.getters調用
            stateGettersProperty(){ //getters屬性調用, 屬性調用會被緩存
                console.log(this.$store.getters.doneTodos);
                console.log(this.$store.getters.doneTodosCount);
            },
            stateGettersMethod(){ //方法調用,每次都會去進行調用,而不會緩存結果。
                console.log(this.$store.getters.getTodoById(2).text);
                console.log(this.$store.getters.getTodoById(3).text);
            },
            addTodo(){ //增加數據
                let count = this.$store.state.todos.length;
                let obj = {
                    id: count + 1,
                    text: (count+1) + '***' + (count+1),
                    done: count % 2
                }
                this.$store.commit('addTodos', obj);
            },

        }
View Code

  mapGetters也是一個輔助函數,可以將store對象中的getter映射到局部計算屬性:

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用對象展開運算符將 getter 混入 computed 對象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}
View Code

  如果你想將一個 getter 屬性另取一個名字,使用對象形式:

mapGetters({
  // 把 `this.doneCount` 映射為 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})
View Code

 

2.3 Vuex之Mutation和mapMutations

  上面說的mapState、getters、mapGetters都是對store對象中的狀態(state)進行應用,如果想更改Vuex的store對象中的狀態(state),必須要用mutation。Vuex中的mutation非常類似於事件:每個mutation都有一個字元串的事件類型(type)和一個回調函數(handler) 。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受state作為第一個參數:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態
      state.count++
    }
  }
})
View Code

  mutation裡面handler調用通過store.commit來調用,調用方式有“載荷(payload)"和“對象風格”兩種方式:

  • 載荷提交方式:
    // ...
    mutations: {
      increment (state, n) {
        state.count += n
      }
    }
    store.commit('increment', 10)
  • 對象風格提交方式:
    mutations: {
      increment (state, payload) {
        state.count += payload.amount
      }
    }
    store.commit({
      type: 'increment',
      amount: 10
    })

    一條重要的原則:mutation必須是同步函數。在組件中使用this.$store.commit('***')提交mutation,或者使用mapMutations輔助函數將組件中的methods映射為store.commit調用。 

 

2.4 Vuex之Action和mapActions

  Action類似於mutation,但是Action提交的是mutation,不能直接變更狀態;另外Action可以包含任意非同步操作。在組件中使用this.$store.dispatch('***')調用action,或者使用mapActions輔助函數將組件中的methods映射為store.dispatch調用。

 

State、Getter、Mutation、Action的一些應用測試代碼見:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageB.vue

 

3、Vuex之模塊化(Module)

   由於使用單一狀態樹,應用的所有狀態(數據)會集中到一個比較大的對象。當應用變得非常複雜時,store對象就有可能變得相當臃腫。為瞭解決這種問題,Vuex允許我們將store分隔成模塊(module)。每個模塊都有自己的state、mutation、action、getter、甚至是嵌套子模塊。

  預設情況下,模塊內容的action、mutation和getter是註冊在全局命名空間的,這樣使得多個模塊能夠對同一mutation或action作出響應。因此為了讓模塊具有更高的封裝度和復用性,我們可以在每個子模塊中添加namespaced: true屬性,這樣表示該模塊成為了帶命名空間的模塊。這樣後面再調用該模塊的getter、action和mutation時需要帶上該模塊名稱+調用的屬性或方法。下麵寫一個示例代碼:

  新建三個js文件moduleA.js、moduleB.js、moduleStore.js,其中moduleA和moduleB分別為子模塊。

moduleA.js:

const state = {
    countA: 99
}

const mutations = {
    increment(state){
        state.countA++
    },
    decrement(state){
        state.countA--
    }
}

const getters = {
    doubleCount(state){
        return state.countA * 2
    }
}

const actions = {
    add({ commit }){
        setTimeout(function(){
            commit('increment')
        }, 50)
    },
    minus({ commit }){
        setTimeout(()=>{
            commit('decrement')
        }, 500)
    }
}

export default {
    namespaced: true, //表示設置命名空間
    state,
    mutations,
    getters,
    actions
}
View Code

moduleB.js: 

const state = {
    countB: 11
}

const mutations = {
    increment(state){
        state.countB++;
    },
    decrement(state){
        state.countB--;
    }
}

//getters類似state裡面屬性的計算屬性
const getters = {
    doubleCount(state){
        return state.countB * 2;
    }
}

const actions = {
    add({ commit }){
        commit('increment')
    },
    minus({ commit }){
        commit('decrement')
    }
}

export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}
View Code

moduleStore.js: 

/*
*  當項目大了後,為了責任清晰,目標明確,更易管理,將store拆成多個module形式
* */
import moduleCountA from './moduleA'
import moduleCountB from './moduleB'
import vuex from 'vuex'
import vue from 'vue'
vue.use(vuex)

export default new vuex.Store({
    modules: {
        moduleCountA,
        moduleCountB
    }
})

  再新建一個VuexPageC.vue頁面,測試調用,js代碼如下:

import { mapGetters, mapActions, mapMutations } from 'vuex'

    export default {
        computed:{
            ...mapGetters({
                doubleCountA: 'moduleCountA/doubleCount',
                doubleConunB: 'moduleCountB/doubleCount'
            })
        },
        methods: {
            ...mapActions({
                //moduleA模塊的actions
                addCountA: 'moduleCountA/add',
                minusCountA: 'moduleCountA/minus',
                //moduleB模塊的actions
                addCountB: 'moduleCountB/add',
                minusCountB: 'moduleCountB/minus'
            }),
            ...mapMutations({
                //moduleA模塊的mutions
                incrementA: 'moduleCountA/increment',
                decrementA: 'moduleCountA/decrement',
                //moduleB模塊的mutions
                incrementB: 'moduleCountB/increment',
                decrementB: 'moduleCountB/decrement'
            }),
        }
    }

頁面效果如圖:

完整VuexPageC.vue頁面代碼見:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageC.vue


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、MySQL邏輯架構 日常在CURD的過程中,都避免不了跟資料庫打交道,大多數業務都離不開資料庫表的設計和SQL的編寫,那如何讓你編寫的SQL語句性能更優呢? 先來整體看下MySQL邏輯架構圖: MySQL整體邏輯架構圖可以分為Server和存儲引擎層。 Server層: Server層涵蓋了My ...
  • 本文內容是採集的好幾位博主的博文進行的一個整合,內容更為精準和詳盡,以下是我參照的幾篇博文地址: 微軟官方文檔:https://docs.microsoft.com/zh-cn/sql/linux/sql-server-linux-setup?view=sql-server-ver15 Callou ...
  • MySQL基礎(4) | 視圖 基本語法 1.創建 語法說明如下。 ``:指定視圖的名稱。該名稱在資料庫中必須是唯一的,不能與其他表或視圖同名。 ``:指定創建視圖的 SELECT 語句,可用於查詢多個基礎表或源視圖。 對於創建視圖中的 SELECT 語句的指定存在以下限制: 用戶除了擁有 CREA ...
  • 一.什麼是MongoDB? MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need (MongoDB是 ...
  • Re:一些百科上的黑幕實現 這裡的黑幕不是那個黑幕啦!你去看看萌娘百科就知道了! 不動它,它就是個黑條子。你盯著它看什麼都不會發生。 當你把滑鼠移到了黑幕上,一些神奇的事情就會發生…… 反正我覺得這很好看(♥∀♥) 不知道你們喜不喜歡呀(≧∇≦)ノ ...
  • 一、 製作一個相片牆 二、 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> *{ margin:0; padding:0; } ul{ height: 400px; ...
  • 正則驗證合法_有效的IP地址(ipv4/ipv6) 不墨跡直接上代碼: 正則表達式: /^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/ JS函數方法: var util = { isValidIp: funct ...
  • 迴圈遍歷是寫程式很頻繁的操作,JavaScript 提供了很多方法來實現。 這篇文章將分別總結數組和對象的遍歷方法,新手可以通過本文串聯起學過的知識。 數組遍歷 方法一:for 迴圈 for 迴圈是使用最多,也是性能優化最好的一種遍歷方式。 ` 方法 方法 方法是 ES5 新增,專為下麵這種累加操作 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...