vuex链接

优势与使用场景

  • Vuex的状态存储是响应式的,可跟踪每一个状态变化,一旦它改变,所有关联组件都会自动更新相对应的数据。
  • 共享数据,解决了非父子组件的消息传递(将数据存放在state中)。
  • 统一状态管理,减少了请求次数,有些情景可以直接从内存中的state获取数据。

    什么时候需要用vuex?

  • 当一个组件需要多次派发事件时。例如购物车数量加减。

  • 跨组件共享数据、跨页面共享数据。例如订单状态更新。
  • 需要持久化的数据。例如登录后用户的信息。
  • 当您需要开发中大型应用,适合复杂的多模块多页面的数据交互,考虑如何更好地在组件外部管理状态时。

    Vuex与全局变量区别

    | vuex | 全局变量 | | —- | —- | | 不能直接改变store里面的变量,由统一的方法修改数据 | 可以任意修改 | | 每个组件可以根据自己vuex的变量名引用不受影响 | 全局变量可能操作命名污染 | | 解决了多组件之间通信的问题 | 跨页面数据共享 | | 适用于多模块、业务关系复杂的中大型项目 | 适用于demo或者小型项目 |

项目结构

使用 Vuex 需要遵守的规则:

  • 应用层级的状态应该集中到单个 store 对象中。
  • 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  • 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 actionmutationgetter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:

  1. ├── pages
  2. ├── static
  3. └── store
  4. ├── index.js # 我们组装模块并导出 store 的地方
  5. ├── actions.js # 根级别的 action
  6. ├── mutations.js # 根级别的 mutation
  7. └── modules # 模块文件夹
  8. ├── cart.js # 购物车模块 模块moduleA
  9. └── products.js # 产品模块 模块moduleA
  10. ├── App.vue
  11. ├── main.js
  12. ├── manifest.json
  13. ├── pages.json
  14. └── uni.scss

核心概念

每一个 Vuex 应用的核心就是 store(仓库),它包含着你的应用中大部分的状态 (state)。
状态管理有5个核心:stategettermutationactionmodule

State

单一状态树,定义应用状态的默认初始值,页面显示所需的数据从该对象中进行读取。

  • Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。它便作为一个“唯一数据源”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
  • 单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
  • 不可直接对 state 进行更改,需要通过 Mutation 方法来更改。

由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:

  1. // 创建一个 Counter 组件
  2. const Counter = {
  3. computed: {
  4. count () {
  5. return store.state.count
  6. }
  7. }
  8. }

每当 store.state.count 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM。
然而,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用 state 的组件中需要频繁地导入,并且在测试组件时需要模拟状态。

使用步骤

Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):

  • 1.在 uni-app 项目根目录下,新建 store 目录,在此目录下新建 index.js 文件。在 index.js 文件配置如下
  • .在 main.js 中导入文件。

image.png

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3. Vue.use(Vuex); //vue的插件机制
  4. //Vuex.Store 构造器选项
  5. const store = new Vuex.Store({
  6. state: { //存放状态
  7. "userName": "Motitol",
  8. "age": 29,
  9. "login":false,
  10. "token":"token789455231",
  11. "avatarUrl":"https://www.baidu.com"
  12. },
  13. mutations: {
  14. login(status, provider) {
  15. console.log(state)
  16. console.log(provider)
  17. state.login = true;
  18. state.token = provider.token;
  19. state.userName = provider.userName;
  20. state.avatarUrl = provider.avatarUrl;
  21. },
  22. logout(state) {
  23. state.login = false;
  24. state.token = '';
  25. state.userName = '';
  26. state.avatarUrl = '';
  27. }
  28. }
  29. })
  30. export default store
  1. import Vue from 'vue'
  2. import App from './App'
  3. import store from './store'
  4. Vue.prototype.$store = store
  5. Vue.config.productionTip = false
  6. App.mpType = 'app'
  7. // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  8. const app = new Vue({
  9. store,
  10. ...App
  11. })
  12. app.$mount()

获取state

  • 1.通过属性访问,需要在根节点注入 store
  • 2.在组件中使用,通过 this.$store 访问到 state 里的数据。
  • 3.通过 mapState 辅助函数获取。 ```

  1. ```
  2. <script>
  3. import store from '@/store/index.js'; //需要引入store
  4. import { mapState } from 'vuex'; //引入mapState
  5. export default {
  6. data() {
  7. return {
  8. temp: '安'
  9. };
  10. },
  11. computed: {
  12. // ...mapState({
  13. // token: function (state) {
  14. // return this.temp + ' ' + state.token
  15. // },
  16. // avatarUrl: state => state.avatarUrl,
  17. // })
  18. ...mapState({
  19. token: state => state.token,
  20. avatarUrl: state => state.avatarUrl
  21. })
  22. }
  23. // computed: mapState([
  24. // 'token', //映射 this.username 为 store.state.username
  25. // 'avatarUrl'
  26. // ])
  27. // computed: mapState({
  28. // // 从state中拿到数据 箭头函数可使代码更简练
  29. // username: state => state.username,
  30. // age: state => state.age,
  31. // })
  32. };
  33. </script>

image.pngimage.png

Getter

可以认为是 store 的计算属性,对 state 的加工,是派生出来的数据。

  • 就像 computed 计算属性一样,getter 返回的值会根据它的依赖被缓存起来,且只有当它的依赖值发生改变才会被重新计算。
  • 可以在多组件中共享 getter 函数,这样做还可以提高运行效率。

uni-app 项目根目录下,store 目录 index.js 文件下:

  1. <!-- 页面路径:store/index.js -->
  2. import Vue from 'vue'
  3. import Vuex from 'vuex'
  4. Vue.use(Vuex);
  5. const store = new Vuex.Store({
  6. state: {
  7. todos: [{
  8. id: 1,
  9. text: '我是内容一',
  10. done: true
  11. },
  12. {
  13. id: 2,
  14. text: '我是内容二',
  15. done: false
  16. }
  17. ]
  18. },
  19. getters: {
  20. doneTodos: state => {
  21. return state.todos.filter(todo => todo.done)
  22. }
  23. }
  24. })
  25. export default store

store 上注册 gettergetter 方法接受以下参数:

  • state, 如果在模块中定义则为模块的局部状态
  • getters, 等同于 store.getters ``` import Vue from ‘vue’ import Vuex from ‘vuex’

Vue.use(Vuex);

const store = new Vuex.Store({ state: { todos: [{ id: 1, text: ‘我是内容一’, done: true }, { id: 2, text: ‘我是内容二’, done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { //state :可以访问数据 //getters:访问其他函数,等同于 store.getters return getters.doneTodos.length }, getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } })

export default store

  1. <a name="Ym402"></a>
  2. #### 获取getters
  3. 1.通过属性访问,Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值。

``` 注意,`getter` 在通过属性访问时是作为 `Vue` 的响应式系统的一部分缓存其中的。 2.通过 this.$store 访问。 ``` ``` 3.通过方法访问。
你也可以通过让 `getter` 返回一个函数,来实现给 `getter` 传参。在你对 `store` 里的数组进行查询时非常有用。
注意,`getter` 在通过方法访问时,每次都会去进行调用,而不会缓存结果。 ``` ``` #### [mapGetters](https://uniapp.dcloud.io/vue-vuex?id=mapgetters) 4.通过 `mapGetters` 辅助函数访问。
`mapGetters` 辅助函数仅仅是将 `store` 中的 `getter` 映射到局部计算属性: ``` ``` 如果你想将一个 `getter` 属性另取一个名字,使用对象形式: ``` ``` ### [Mutation](https://uniapp.dcloud.io/vue-vuex?id=mutation) **Vuex中store数据改变的唯一方法就是mutation** #### 基本信息 ``` import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1 }, mutations: { add(state) { // 变更状态 state.count += 2 } } }) export default store ``` ``` ``` #### 传入参数 - 传入一个参数 - 传入一个对象 ``` import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1 }, mutations: { add(state, n) { state.count += n }, aadd(state, payload) { state.count += payload.amount } } }) export default store ``` ``` ``` #### 提交方式 - 1.对象风格的提交方式。(store.commit) ```

mutations: { add(state, payload) { state.count += payload.amount } }

  1. - 通过 `mapMutations` 辅助函数提交
  2. <br />

  1. <a name="action"></a>
  2. ### [Action](https://uniapp.dcloud.io/vue-vuex?id=action)
  3. > `action` 类似于 `mutation` ,不同在于:
  4. > - action 提交的是 `mutation`,通过 `mutation` 来改变 `state` ,而不是直接变更状态。
  5. > - action 可以包含任意异步操作。
  6. <a name="oWZ3U"></a>
  7. #### 注册action

import Vue from ‘vue’ import Vuex from ‘vuex’

Vue.use(Vuex);

const store = new Vuex.Store({ state: { count: 1 }, mutations:{ add(state) { // 变更状态 state.count += 2 } }, //actions:{ // addCountAction (context) { // context.commit(‘add’) // } //} actions: { //参数解构 addCountAction ({commit}) { commit(‘add’) } } }) export default store ```

分发Action

  • actions 通过 store.dispatch 方法触发。
  • actions 支持以载荷形式分发。
  • actions 支持以对象形式分发。
  • 通过 mapActions 辅助函数分发。
  • 组合action。

Module

  • store 文件夹下新建 modules 文件夹,并在下面新建 moduleA.jsmoduleB.js 文件用来存放 vuexmodules 模块。
  • main.js 文件中引入 store。
  • 在项目根目录下,新建 store 文件夹,并在下面新建 index.js 文件,作为模块入口,引入各子模块。
  • 子模块 moduleA 页面内容。
  • 子模块 moduleB 页面内容。
  • 在页面中引用组件 myButton ,并通过 mapState 读取 state 中的初始数据。
  • 在组件 myButton中,通过 mutations 操作刷新当前时间。<br />