1、Vuex 状态管理

Vuex官网

Vuex是一个专门为 Vue.js 应用开发的状态管理模式。它采用集中式储存来管理应用程序中所又组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex也集成到了Vue的官方调试工具vue-devtools中,提供了诸如零配置的time-travel调试状态快照导入导出等高级调试功能。

Vuex的工作原理图:
在这里插入图片描述

2、表单处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
<div id="app">
    <my-component></my-component>
</div>

<script src="VueJs/vue.js"></script>
<script src="VueJs/vuex.js"></script>
<script>
  Vue.component('MyComponent', {
    computed: {
      ...Vuex.mapState([
        'message'
      ])
    },
    template: `<input type="text" v-model="message">`
  })

  // 创建Vuex容器
  const store = new Vuex.Store({
    strict: true,
    state: {
      message: 'Vue.js 从入门到秃顶'
    },
    mutations: {
      updateMessage(state, msg) {
        state.message = msg
      }
    }
  })

  new Vue({
    el: '#app',
    store
  })
</script>
</body>
</html>

2.1、如果希望实现双向绑定,可以如下修改:

  • 源代码
    computed: {
      ...Vuex.mapState([
        'message'
      ])
    },
  • 修改后(使用计算属性的 set 方法来提交 mutation
    computed: {
      message: {
        get() {
          return this.$store.state.message
        },
        set(value) {
          this.$store.commit('updateMessage', value)
        }
      }
    }

在这里插入图片描述

3、模块

3.1、模块的整体结构

应该有小伙伴注意到这里 state: () => ({ ... }) 与之前的写法不太一样,这是因为与 Vue中 data 的情况是一样的,区分局部变量和全局变量。

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 的状态

3.2、模块局部

export const moduleA = {
  state: () => ({ ... }),
  mutations: { .. },
  getters: { ... },
  actions: { ... },
  // 嵌套模块
  modules: {
    child: {
      state: () => ({}),
      getters: { ... }
      }
    }
  }
}

3.3、案例

3.3.1、store.js

import Vue from 'vue'
import Vuex from 'vuex'
import {moduleA} from './modules/moduleA'
import {moduleB} from './modules/moduleB'

Vue.use(Vuex)

// 创建Vuex容器
export default new Vuex.Store({
  strict: true,
  state: {
    count: 25
  },
  modules: {
    a: moduleA,
    b: moduleB
  },
  mutations: {
    someMutation(state) {
      state.count += 29
    }
  },
  getters: {
    someOtherGetter(state) {
      console.log('root: someOtherGetter')
      return state.count * 2
    }
  },
  actions: {
    someOtherAction(ctx, payload) {
      console.log('root: actions -> someOtherAction' + ctx, payload)
      return 'root: actions -> someOtherAction'
    },
  }
})

3.3.2、moduleA.js

export const moduleA = {
  namespaced: true, // 空间命名 即 可以理解为 getters、actions 都带有 moduleA 前缀,支持嵌套。
  state: () => ({
    // state 写成 方法的样式,即 局部状态
    count: 0
  }),
  mutations: {
    increment(state) {
      // 这里的 `state` 对象是模块的局部状态
      state.count++
    },
    someMutation(state) {
      state.count += 17
    }
  },
  getters: {
    someOtherGetter(state) {
      console.log('moduleA: someOtherGetter')
      return state.count * 2
    },
    // 对于模块内部的 getter,根节点状态会作为第三个参数(rootState)暴露出来
    sumWithRootCount(state, getters, rootState) {
      return state.count + rootState.count
    },
    // 在这个模块的 getter 中,`getters` 被局部化了
    // 你可以使用 getter 的第四个参数来调用 `rootGetters`
    someGetter(state, getters, rootState, rootGetters) {
      // console.log(getters.someOtherGetter) // -> 'moduleA/someOtherGetter'
      // console.log(rootGetters.someOtherGetter) // -> 'someOtherGetter'
      return 'getters.someOtherGetter: ' + getters.someOtherGetter + '; rootGetters.someOtherGetter: ' + rootGetters.someOtherGetter
    },
  },
  actions: {
    // 这里的传递没有顺序,因为{}内参数(state, commit, dispatch, rootState, getters, rootGetters)都是 context 的属性
    incrementIfOddOnRootSum({state, commit, rootState}) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    },
    // 在这个模块中, dispatch 和 commit 也被局部化了
    // 他们可以接受 `root` 属性以访问根 dispatch 或 commit
    someAction({dispatch, commit, getters, rootGetters}) {
      console.log(getters.someGetter) // -> 'moduleA/someGetter'
      console.log(rootGetters.someGetter) // -> 'someGetter'

      dispatch('someOtherAction') // -> 'moduleA/someOtherAction'
      dispatch('someOtherAction', null, {root: true}) // -> 'someOtherAction'

      commit('someMutation') // -> 'moduleA/someMutation'
      commit('someMutation', null, {root: true}) // -> 'someMutation'
    },
    someOtherAction(ctx, payload) {
      console.log('moduleA: actions -> someOtherAction' + ctx, payload)
      return 'moduleA: actions -> someOtherAction'
    },
    someRootAction: { // -> 'someRootAction'
      root: true, // 在带命名空间的模块注册全局 action
      handler(namespacedContext, payload) {
        console.log('moduleA: 在带命名空间的模块注册全局 action -> someRootAction')
        return namespacedContext, payload
      }
    }
  },
  // 嵌套模块
  modules: {
    // 继承父模块的命名空间
    myPage: {
      state: () => ({}),
      getters: {
        profile() {
          return 'moduleA: 嵌套 profile'
        } // -> getters['moduleA/profile']
      }
    },

    // 进一步嵌套命名空间
    posts: {
      namespaced: true,
      state: () => ({}),
      getters: {
        popular() {
          return 'moduleA: 嵌套 posts/popular'
        } // -> getters['moduleA/posts/popular']
      }
    }
  }
}

3.3.3、moduleB.js

export const moduleB = {
  namespaced: true,
  state: () => ({
    count: 100
  }),
  mutations: {
    increment(state) {
      state.count += 2
    }
  },
  getters: {
    someOtherGetter(state) {
      console.log('moduleB: someOtherGetter')
      return state.count * 2
    },
    sumWithRootCount(state, getters, rootState) {
      return state.count + rootState.count
    },
    someGetter(state, getters, rootState, rootGetters) {
      return 'getters.someOtherGetter: ' + getters.someOtherGetter + '; rootGetters.someOtherGetter: ' + rootGetters.someOtherGetter
    },
  },
  actions: {
    incrementIfOddOnRootSum({state, commit, rootState}) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    },
    someAction({dispatch, commit, getters, rootGetters}) {
      console.log(getters.someGetter)
      console.log(rootGetters.someGetter)

      dispatch('someOtherAction')
      dispatch('someOtherAction', null, {root: true})

      commit('someMutation')
      commit('someMutation', null, {root: true})
    },
    someOtherAction(ctx, payload) {
      console.log('moduleB: actions -> someOtherAction' + ctx, payload)
      return 'moduleB: actions -> someOtherAction'
    }
  },
  // 嵌套模块
  modules: {
    myPage: {
      state: () => ({}),
      getters: {
        profile() {
          return 'moduleB: 嵌套 profile'
        }
      }
    },

    posts: {
      namespaced: true,
      state: () => ({}),
      getters: {
        popular() {
          return 'moduleB: 嵌套 posts/popular'
        }
      }
    }
  }
}

3.3.4、Vue组件引用

<template>
    <div class="hello">
        <h3>moduleA</h3>
        <table>
            <tr><td>count</td><td>: </td><td>{{ count }}</td></tr>
            <tr><td>sumWithRootCount</td><td>: </td><td>{{ sumWithRootCount }}</td></tr>
            <tr><td>someGetter</td><td>: </td><td>{{ someGetter }}</td></tr>
            <tr><td>posts/popular</td><td>: </td><td>{{ popularA }}</td></tr>
            <tr><td>someOtherAction</td><td>: </td><td>{{ someOtherAction() }}</td></tr>
        </table>

        <h3>moduleB</h3>
        <table>
            <tr><td>countB</td><td>: </td><td>{{ countB }}</td></tr>
            <tr><td>sumWithRootCountB</td><td>: </td><td>{{ sumWithRootCountB }}</td></tr>
            <tr><td>someGetterB</td><td>: </td><td>{{ someGetterB }}</td></tr>
            <tr><td>posts/popular</td><td>: </td><td>{{ popularB }}</td></tr>
            <tr><td>someOtherActionB</td><td>: </td><td>{{ someOtherActionB() }}</td></tr>
        </table>

        <h3>Root</h3>
        <table>
            <tr><td>someOtherActionRoot</td><td>: </td><td>{{ someOtherActionRoot() }}</td></tr>
            <tr><td>someRootAction</td><td>: </td><td>{{ someRootAction() }}</td></tr>
        </table>
    </div>
</template>

<script>
import {mapActions, mapGetters, mapState} from 'vuex'

export default {
    computed: {
        ...mapState('a', [
            'count'
        ]),
        ...mapGetters('a', [
            'sumWithRootCount',
            'someGetter',
            'profile',
        ]),
        ...mapGetters('a/posts', {
            popularA: 'popular'
        }),

        ...mapState('b', {
            countB: 'count'
        }),
        ...mapGetters('b', {
            sumWithRootCountB: 'sumWithRootCount',
            someGetterB: 'someGetter',
            profileB: 'profile',
        }),
        ...mapGetters('b/posts', {
            popularB: 'popular'
        }),
    },
    methods: {
        ...mapActions('a', [
            'someOtherAction',
        ]),
        ...mapActions('b', {
            someOtherActionB: 'someOtherAction',
        }),
        ...mapActions([
            'someRootAction'
        ]),
        ...mapActions({
            someOtherActionRoot: 'someOtherAction',
        })
    }
}
</script>

<style scoped>

</style>

3.3.5、结果

在这里插入图片描述

4、Vuex刷新后数据丢失问题

4.1、方法一(本人验证可用)

utils.js

/**
 * 深度复制
 * @param o 随意类型
 * @returns {string|number|boolean|{}|*[]}
 */
export function deepClone(o) {
  // 判断如果不是引用类型,直接返回数据即可
  if (typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' || typeof o === 'undefined') {
    return o
  } else if (Array.isArray(o)) { // 如果是数组,则定义一个新数组,完成复制后返回
    // 注意,这里判断数组不能用typeof,因为typeof Array 返回的是object
    const _arr = []
    o.forEach(item => {
      _arr.push(item)
    })
    return _arr
  } else if (typeof o === 'object') {
    const _o = {}
    for (const key in o) {
      _o[key] = deepClone(o[key])
    }
    return _o
  }
}

/**
 * 数据持久化,解决Vuex刷新数据丢失问题
 * @param self
 */
export function dataPersistence(self) {
  // 数据持久化操作
  window.addEventListener('beforeunload', () => {
    localStorage.setItem('stateInfo', JSON.stringify(self.$store.state))
  })
  if (localStorage.getItem('stateInfo')) {
    self.$store.replaceState(
      Object.assign(
        {},
        self.$store.state,
        JSON.parse(localStorage.getItem('stateInfo'))
      )
    )
  }

  localStorage.removeItem('stateInfo')
  // console.log('持久化:')
  // console.log(this.$store.state)
}

使用

<script>
import { dataPersistence } from '@/utils/utils'

export default {
  created() {
    // 数据持久化
    dataPersistence(this)
   }
}
</script>

4.2、其他方法(本人未验证)

  • https://www.cnblogs.com/enhengenhengNymph/p/13748113.html
Logo

前往低代码交流专区

更多推荐