VueX的基本使用


VueX的基本使用

1、什么是VueX

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

以上是官方文檔的介紹,我淺顯的理解VueX就是用於存儲一些全局配置,可以在不同的組件中使用這些全局配置,根據不同的使用場景提供了異步獲取和計算屬性式獲取的方式。

2、VueX的使用場景

傳統傳值方式:

VueX傳值方式:

從上圖我們可以看出,使用VueX后,組件之間值的傳遞變的異常簡單。可以進行統一管理,統一使用。減少了請求后台的次數。沒有了繁瑣的props和$refs。

但是VueX也有他的弊端,例如刷新頁面后state將會變為初始狀態,對於頻繁變化的結果也不適於存儲在VueX內,因此不建議將所有狀態都使用VueX來管理,否則你需要在每個使用的頁面都調用一次actions(代碼分層的方式除外)。

VueX最常見的使用場景就是存儲用戶的信息、保存token、主題配置等。一種更加高級的用法是使用VueX將和后端交互的axios異步請求進行封裝,實現代碼的分層,讓組件中的代碼更加關注與頁面交互

3、quickstart

安裝vuex

npm install vuex --save

在根目錄創建store目錄,在目錄內創建index.js,在其內部創建

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules: {}
})

在main.js內引用store

import Vue from 'vue'
import App from './App.vue'
import router from './router' //重要
import store from './store'  //重要
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)
Vue.config.productionTip = false

new Vue({
  router, 
  store, //重要
  render: h => h(App)
}).$mount('#app')

如果使用腳手架創建項目,且默認選擇了vuex,系統會自動為我們創建上述內容。

4、state

4.1、state介紹

VueX中的state就是真正保存數據的地方,它的寫法和作用類似於vue對象內的data。

  • state內存放的數據如果發生了修改,依賴這個屬性的組件的數據也會發生變化。
  • state內的屬性無法直接修改,必須通過mutations修改。
  • state內可以存儲一般數據類型,也可以存儲對象類型。

4.2、在state內添加一些數據

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    title: 'hello world',
    userInfo: {
      name: 'rayfoo',
      age: 24,
      car: ['Porsche', 'BMW']
    }
  },
  mutations: {},
  actions: {},
  modules: {}
})

4.3、在頁面中使用state

// 在.vue內使用
<h1 v-text="$store.state.title"></h1>
{{$store.state.title}}

// 在js中使用
this.$store.state.title

4.4、語法糖...mapState

為了簡化state的訪問方式,VueX提供了訪問語法糖,可以像訪問當前項目計算屬性一樣訪問state。

import { mapState } from 'vuex'
export default {
  computed: {
    ...mapState(['title'])
  }
}

頁面調用

<h1 v-text="title"></h1>

5、mutations

5.1、mutations介紹

前面我們介紹了,state內的數據是無法直接修改的。如果要修改state內的元素,必須使用mutations。如果你學過java語言,那么可以用setter方法來簡單的理解mutations。mutations的存在就是為了修改state內的數據。

由於mutations和我們下面要說的actions使用時非常相似,所以mutations的名稱通常用大寫加下划線表示

4.2、聲明mutations

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    title: 'hello world'
  },
  mutations: {
    SET_TITLE (state, _title) {
      state.title = _title
    }
  },
  actions: {},
  modules: {}
})

我們可以看到,mutations的寫法類似於method,它的第一個參數是固定的state,表示要修改的state。后面的參數我們可以自由指定或者省略。

上面的案例中我們通過setTitle將state內的title修改為了新的title,而新的title可以由參數的形式傳遞進來。

4.3、調用mutations

上面的案例,我們創建了一個mutations,它只是一個聲明的過程,如果我們需要調用,則需要使用下面的代碼:

this.$store.SET_TITLE("setTitle","hello Vuex")

4.4、語法糖...mapMutations

使用this.$store.commit這種操作形式過於繁瑣,mutations提供了語法糖,能更像調用當前頁面的methods一樣對其調用。

用法如下

<script>
import { mapMutations } from 'vuex'
export default {
  created () {
    // 使用setTitle
    this.SET_TITLE('你好,mapMutations')
  },
  methods: {
    ...mapMutations(['SET_TITLE'])
  }
}
</script>

6、getters

6.1、getters介紹

前面我們用java中的setter比喻了mutations,那getters也可以比喻為java中的getter方法。如果沒學過java也沒關系,你一定用過Vue中的計算屬性computed,getters的用法就類似於computed。

getters可以單純的獲取state中的內容,也可以對結果做過濾、計算、截取等等一系列的操作,來拿到我們需要的結果。

getters默認是不支持參數的,我們可以通過返回一個函數的形式來完成參數的傳遞。

6.2、聲明getters

下面的案例我們通過getter,將所有的title以加上書名號的形式返回:

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    title: 'hello world'
  },
  mutations: {},
  actions: {},
  getters: {
    getFomatTitle (state) {
      return `《${state.title}》`
    }
  },
  modules: {}
})

6.3、使用getters

//.vue頁面內
$store.getters.getFomatTitle

// javascript
this.$store.getters.getFomatTitle

6.4、向getters傳遞參數

下面的案例演示了通過返回函數的形式向getters內傳遞參數

聲明

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    studentList: [
      { id: 1, name: 'zhangsan' },
      { id: 2, name: 'lisi' },
      { id: 3, name: 'wangwu' }
    ]
  },
  mutations: {},
  actions: {},
  getters: {
    getStudentById: state => id => {
      return state.studentList.find(student => student.id == id)
    }
  },
  modules: {}
})

調用

this.$store.getters.getStudentById(1)

4.5、語法糖...mapGetters

和mutations意義,getters也擁有自己的語法糖,下面的案例演示了如何使用getters的語法糖

import { mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters(['getFomatTitle', 'getStudentById'])
  }
}

通過...mapGetters引入后,就可以像使用當前組件中的計算屬性一樣使用VueX的getters了。

頁面使用

<h3 v-text="student.name"></h3>
<h3 v-text="getStudentById(2).name"></h3>

7、actions

7.1、actions介紹

actions可以理解為mutations的異步版本,由於修改state內的數據必須使用mutations,所以actions內還是必須使用mutations的。

7.2、聲明actions

在vue里最常見的異步操作就是調用axios請求,下面我們通過一個actions調用axios的案例來認識一下它。

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    title: 'hello world'
  },
  mutations: {
    SET_TITLE (state, _title) {
      state.title = _title
    }
  },
  actions: {
    setAsyncTitle (context, title) {
      axios.get(`/api/get-title?title=${title}`).then(resp => {
        context.commit('SET_TITLEX', resp.data)
      })
    }
  },
  getters: {},
  modules: {}
})

7.3、使用actions

this.$store.dispatch('setAsyncTitle', '你好,Axios!!!')

7.4、語法糖...mapActions

import { mapActions } from 'vuex'
export default {
  created () {
    this.setAsyncTitle('你好,Axios!!!')
  },
  methods: {
    ...mapActions(['setAsyncTitle'])
  }
}

8、modules

8.1、modules介紹

前面的案例我們都是在VueX自動生成的./store/index.js中編寫的,真實的項目中,VueX中保存的內容會很多,保存在一個文件中會很難管理,通過modules可以更方便的管理VueX。

每個module都可以擁有自己的state、mutations、getters、actions。

在實際開發中,modules中通常不會包含getters,而是單獨創建一個js來保存VueX中的所有getters

8.2、modules的使用

簡單的使用形式:

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

8.3、多文件形式引用Modules

多文件的引用形式:以下代碼引用自ruoyi-vue

module

import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'

const user = {
  state: {
    token: getToken(),
    name: '',
    avatar: '',
    roles: [],
    permissions: []
  },

  mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_NAME: (state, name) => {
      state.name = name
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    },
    SET_PERMISSIONS: (state, permissions) => {
      state.permissions = permissions
    }
  },

  actions: {
    // 登錄
    Login({ commit }, userInfo) {
     // 略
    },

    // 獲取用戶信息
    GetInfo({ commit, state }) {
      // 略
    },

    // 退出系統
    LogOut({ commit, state }) {
      // 略
    },

    // 前端 登出
    FedLogOut({ commit }) {
      return new Promise(resolve => {
        commit('SET_TOKEN', '')
        removeToken()
        resolve()
      })
    }
  }
}

export default user

getters

const getters = {
  sidebar: state => state.app.sidebar,
  size: state => state.app.size,
  device: state => state.app.device,
  visitedViews: state => state.tagsView.visitedViews,
  cachedViews: state => state.tagsView.cachedViews,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  introduction: state => state.user.introduction,
  roles: state => state.user.roles,
  permissions: state => state.user.permissions,
  permission_routes: state => state.permission.routes,
  topbarRouters:state => state.permission.topbarRouters,
  defaultRoutes:state => state.permission.defaultRoutes,
  sidebarRouters:state => state.permission.sidebarRouters,
}
export default getters

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import tagsView from './modules/tagsView'
import permission from './modules/permission'
import settings from './modules/settings'
import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    app,
    user,
    tagsView,
    permission,
    settings
  },
  getters
})

export default store

使用

// state and getters
this.$store.state.模塊名.state

// actions
this.$store.dispatch('模塊名/actionsName',prams)

// mutations 由於mutations不區分模塊,所以注意命名全局唯一性
this.$store.commit("mutationsName", params);

// 因為上面說了 getters沒有在每個modules內都寫,所以可以直接用
this.getters.gettersName

// 如果使用module內的getters
this.$store.getters["模塊名/gettersName"]

8.4、模塊中的內容使用...mapXXX

# state
...mapState({
  userName: state => state.user.name,
  userAge: state=> state.user.age
})

# mutations getters actions 沒有命名空間的限定,所以要保證全局的唯一性
...mapMutations(['mutationsName'])
...mapGetters(['gettersName'])
...mapActions(['actionsName'])

9、刷新頁面數據丟失問題

雖然VueX可以保存全局狀態,但頁面刷新后。VueX中的狀態會被重新初始化。如果當前頁面的值恰好是在其他組件內mutations或actions后產生的,那值可能會顯示異常,造成數據丟失的感覺。例如如果把獲取用戶信息的操作放在了登錄頁面,那么進入系統后刷新就會發生上述情況。

解決辦法有如下三種思路:

1、將vuex中的數據保存到瀏覽器緩存中如(cookie、localStorage和sessionStorage)。

2、在會發生數據丟失的頁面重新發送actions、mutations請求。

方法1的缺點是不安全且不適用於大量數據的存儲,方法2適用於少量數據且接口訪問速度比較快的情況。所以有了方案3,方案3就是方案1和方案2的結合。

3、頁面刷新的時候異步請求后台數據,然后動態更新vuex中的數據,其中會有一種情況就是,網絡延遲、數據量大的問題。此時還沒等vuex獲取到后台返回的數據,頁面就已經加載完成了,這樣就會造成數據丟失。所以該解決方案就是,監聽瀏覽器刷新前事件,在瀏覽器刷新之前就把vuex里的數據保存至sessionStorage中,刷新成功后如果異步請求的數據還沒返回則直接獲取sessionStorage里的數據,否則獲取vuex里的數據。(只有刷新后還沒取到后台數據,才會從sessionStorage里取。確保數據的安全性,就算獲取sessionStorage里的數據也是安全的,因為每次刷新都會重新賦值,不必擔心數據被篡改問題,其次就是對sessionStorage里的數據做了加密操作)

參考:

VueX官方文檔

什么是vuex?怎么使用?在那種場景下使用

如何解決vuex頁面刷新數據丟失問題?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM