Vue2向Vue3过度Vuex核心概念module模块

深碍√TFBOYSˉ_ 2024-03-24 21:51 126阅读 0赞

目录

    • 1 核心概念 - module
      • 1.目标
      • 2.问题
      • 3.模块定义 - 准备 state
    • 2 获取模块内的state数据
      • 1.目标:
      • 2.使用模块中的数据
      • 3.代码示例
    • 3 获取模块内的getters数据
      • 1.目标:
      • 2.语法:
      • 3.代码演示
    • 4 获取模块内的mutations方法
      • 1.目标:
      • 2.注意:
      • 3.调用方式:
      • 4.代码实现
    • 5 获取模块内的actions方法
      • 1.目标:
      • 2.注意:
      • 3.调用语法:
      • 4.代码实现
    • 6 Vuex模块化的使用小结
      • 1.直接使用
      • 2.借助辅助方法使用
    • 7 综合案例 - 创建项目
    • 8 综合案例-构建vuex-cart模块
    • 9 综合案例-准备后端接口服务环境
    • 10 综合案例-请求动态渲染数据
      • 1.目标
    • 11 综合案例-修改数量
    • 12 综合案例-底部总价展示

1 核心概念 - module

在这里插入图片描述

1.目标

掌握核心概念 module 模块的创建

2.问题

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

这句话的意思是,如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护

由此,又有了Vuex的模块化

在这里插入图片描述

3.模块定义 - 准备 state

定义两个模块 usersetting

user中管理用户的信息状态 userInfo modules/user.js

  1. const state = {
  2. userInfo: {
  3. name: 'zs',
  4. age: 18
  5. }
  6. }
  7. const mutations = {}
  8. const actions = {}
  9. const getters = {}
  10. export default {
  11. state,
  12. mutations,
  13. actions,
  14. getters
  15. }

setting中管理项目应用的 主题色 theme,描述 desc, modules/setting.js

  1. const state = {
  2. theme: 'dark'
  3. desc: '描述真呀真不错'
  4. }
  5. const mutations = {}
  6. const actions = {}
  7. const getters = {}
  8. export default {
  9. state,
  10. mutations,
  11. actions,
  12. getters
  13. }

store/index.js文件中的modules配置项中,注册这两个模块

  1. import user from './modules/user'
  2. import setting from './modules/setting'
  3. const store = new Vuex.Store({
  4. modules:{
  5. user,
  6. setting
  7. }
  8. })

使用模块中的数据, 可以直接通过模块名访问 $store.state.模块名.xxx => $store.state.setting.desc

也可以通过 mapState 映射

2 获取模块内的state数据

1.目标:

掌握模块中 state 的访问语法

尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的 state 中,属性名就是模块名

在这里插入图片描述

2.使用模块中的数据

  1. 直接通过模块名访问 $store.state.模块名.xxx
  2. 通过 mapState 映射:

    1. 默认根级别的映射 mapState([ ‘xxx’ ])
    2. 子模块的映射 :mapState(‘模块名’, [‘xxx’]) - 需要开启命名空间 namespaced:true

modules/user.js

  1. const state = {
  2. userInfo: {
  3. name: 'zs',
  4. age: 18
  5. },
  6. myMsg: '我的数据'
  7. }
  8. const mutations = {
  9. updateMsg (state, msg) {
  10. state.myMsg = msg
  11. }
  12. }
  13. const actions = {}
  14. const getters = {}
  15. export default {
  16. namespaced: true,
  17. state,
  18. mutations,
  19. actions,
  20. getters
  21. }

3.代码示例

$store直接访问

  1. $store.state.user.userInfo.name

mapState辅助函数访问

  1. ...mapState('user', ['userInfo']),
  2. ...mapState('setting', ['theme', 'desc']),

3 获取模块内的getters数据

1.目标:

掌握模块中 getters 的访问语

2.语法:

使用模块中 getters 中的数据:

  1. 直接通过模块名访问$store.getters['模块名/xxx ']
  2. 通过 mapGetters 映射

    1. 默认根级别的映射 mapGetters([ 'xxx' ])
    2. 子模块的映射 mapGetters('模块名', ['xxx']) - 需要开启命名空间

3.代码演示

modules/user.js

  1. const getters = {
  2. // 分模块后,state指代子模块的state
  3. UpperCaseName (state) {
  4. return state.userInfo.name.toUpperCase()
  5. }
  6. }

Son1.vue 直接访问getters

  1. <!-- 测试访问模块中的getters - 原生 -->
  2. <div>{
  3. { $store.getters['user/UpperCaseName'] }}</div>

Son2.vue 通过命名空间访问

  1. computed:{
  2. ...mapGetters('user', ['UpperCaseName'])
  3. }

4 获取模块内的mutations方法

1.目标:

掌握模块中 mutation 的调用语法

2.注意:

默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。

3.调用方式:

  1. 直接通过 store 调用 $store.commit(‘模块名/xxx ‘, 额外参数)
  2. 通过 mapMutations 映射

    1. 默认根级别的映射 mapMutations([ ‘xxx’ ])
    2. 子模块的映射 mapMutations(‘模块名’, [‘xxx’]) - 需要开启命名空间

4.代码实现

modules/user.js

  1. const mutations = {
  2. setUser (state, newUserInfo) {
  3. state.userInfo = newUserInfo
  4. }
  5. }

modules/setting.js

  1. const mutations = {
  2. setTheme (state, newTheme) {
  3. state.theme = newTheme
  4. }
  5. }

Son1.vue

  1. <button @click="updateUser">更新个人信息</button>
  2. <button @click="updateTheme">更新主题色</button>
  3. export default {
  4. methods: {
  5. updateUser () {
  6. // $store.commit('模块名/mutation名', 额外传参)
  7. this.$store.commit('user/setUser', {
  8. name: 'xiaowang',
  9. age: 25
  10. })
  11. },
  12. updateTheme () {
  13. this.$store.commit('setting/setTheme', 'pink')
  14. }
  15. }
  16. }

Son2.vue

  1. <button @click="setUser({ name: 'xiaoli', age: 80 })">更新个人信息</button>
  2. <button @click="setTheme('skyblue')">更新主题</button>
  3. methods:{
  4. // 分模块的映射
  5. ...mapMutations('setting', ['setTheme']),
  6. ...mapMutations('user', ['setUser']),
  7. }

5 获取模块内的actions方法

1.目标:

掌握模块中 action 的调用语法 (同理 - 直接类比 mutation 即可)

2.注意:

默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。

3.调用语法:

  1. 直接通过 store 调用 $store.dispatch(‘模块名/xxx ‘, 额外参数)
  2. 通过 mapActions 映射

    1. 默认根级别的映射 mapActions([ ‘xxx’ ])
    2. 子模块的映射 mapActions(‘模块名’, [‘xxx’]) - 需要开启命名空间

4.代码实现

需求:

在这里插入图片描述

modules/user.js

  1. const actions = {
  2. setUserSecond (context, newUserInfo) {
  3. // 将异步在action中进行封装
  4. setTimeout(() => {
  5. // 调用mutation context上下文,默认提交的就是自己模块的action和mutation
  6. context.commit('setUser', newUserInfo)
  7. }, 1000)
  8. }
  9. }

Son1.vue 直接通过store调用

  1. <button @click="updateUser2">一秒后更新信息</button>
  2. methods:{
  3. updateUser2 () {
  4. // 调用action dispatch
  5. this.$store.dispatch('user/setUserSecond', {
  6. name: 'xiaohong',
  7. age: 28
  8. })
  9. },
  10. }

Son2.vue mapActions映射

  1. <button @click="setUserSecond({ name: 'xiaoli', age: 80 })">一秒后更新信息</button>
  2. methods:{
  3. ...mapActions('user', ['setUserSecond'])
  4. }

6 Vuex模块化的使用小结

1.直接使用

  1. state —> $store.state.模块名.数据项名
  2. getters —> $store.getters[‘模块名/属性名’]
  3. mutations —> $store.commit(‘模块名/方法名’, 其他参数)
  4. actions —> $store.dispatch(‘模块名/方法名’, 其他参数)

2.借助辅助方法使用

1.import { mapXxxx, mapXxx } from ‘vuex’

computed、methods: {

// …mapState、…mapGetters放computed中;

// …mapMutations、…mapActions放methods中;

…mapXxxx(‘模块名’, [‘数据项|方法’]),

…mapXxxx(‘模块名’, { 新的名字: 原来的名字 }),

}

2.组件中直接使用 属性 { { age }} 或 方法 @click="updateAge(2)"

7 综合案例 - 创建项目

  1. 脚手架新建项目 (注意:勾选vuex)

    版本说明:

    vue2 vue-router3 vuex3

    vue3 vue-router4 vuex4/pinia

    vue create vue-cart-demo

  2. 将原本src内容清空,替换成教学资料的《vuex-cart-准备代码》

在这里插入图片描述

需求:

  1. 发请求动态渲染购物车,数据存vuex (存cart模块, 将来还会有user模块,article模块…)
  2. 数字框可以修改数据
  3. 动态计算总价和总数量

8 综合案例-构建vuex-cart模块

  1. 新建 store/modules/cart.js

    export default {
    namespaced: true,
    state () {

    1. return {
    2. list: []
    3. }

    },
    }

  2. 挂载到 vuex 仓库上 store/cart.js

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

    import cart from ‘./modules/cart’

    Vue.use(Vuex)

    const store = new Vuex.Store({
    modules: {

    1. cart

    }
    })

    export default store

9 综合案例-准备后端接口服务环境

  1. 安装全局工具 json-server (全局工具仅需要安装一次)

    yarn global add json-server 或 npm i json-server -g

  2. 代码根目录新建一个 db 目录

  3. 将资料 index.json 移入 db 目录
  4. 进入 db 目录,执行命令,启动后端接口服务 (使用–watch 参数 可以实时监听 json 文件的修改)

    json-server —watch index.json

10 综合案例-请求动态渲染数据

1.目标

请求获取数据存入 vuex, 映射渲染

在这里插入图片描述

  1. 安装 axios

    yarn add axios

  2. 准备actions 和 mutations

    import axios from ‘axios’

    export default {
    namespaced: true,
    state () {

    1. return {
    2. list: []
    3. }

    },
    mutations: {

    1. updateList (state, payload) {
    2. state.list = payload
    3. }

    },
    actions: {

    1. async getList (ctx) {
    2. const res = await axios.get('http://localhost:3000/cart')
    3. ctx.commit('updateList', res.data)
    4. }

    }
    }

  3. App.vue页面中调用 action, 获取数据

    import { mapState } from ‘vuex’

    export default {
    name: ‘App’,
    components: {

    1. CartHeader,
    2. CartFooter,
    3. CartItem

    },
    created () {

    1. this.$store.dispatch('cart/getList')

    },
    computed: {

    1. ...mapState('cart', ['list'])

    }
    }

  4. 动态渲染

cart-item.vue

  1. <template>
  2. <div class="goods-container">
  3. <!-- 左侧图片区域 -->
  4. <div class="left">
  5. <img :src="item.thumb" class="avatar" alt="">
  6. </div>
  7. <!-- 右侧商品区域 -->
  8. <div class="right">
  9. <!-- 标题 -->
  10. <div class="title">{
  11. {item.name}}</div>
  12. <div class="info">
  13. <!-- 单价 -->
  14. <span class="price">¥{
  15. {item.price}}</span>
  16. <div class="btns">
  17. <!-- 按钮区域 -->
  18. <button class="btn btn-light">-</button>
  19. <span class="count">{
  20. {item.count}}</span>
  21. <button class="btn btn-light">+</button>
  22. </div>
  23. </div>
  24. </div>
  25. </div>
  26. </template>
  27. <script>
  28. export default {
  29. name: 'CartItem',
  30. props: {
  31. item: Object
  32. },
  33. methods: {
  34. }
  35. }
  36. </script>

11 综合案例-修改数量

在这里插入图片描述

  1. 注册点击事件


    {
    {item.count}}

  2. 页面中dispatch action

    onBtnClick (step) {
    const newCount = this.item.count + step
    if (newCount < 1) return

    // 发送修改数量请求
    this.$store.dispatch(‘cart/updateCount’, {

    1. id: this.item.id,
    2. count: newCount

    })
    }

  3. 提供action函数

    async updateCount (ctx, payload) {
    await axios.patch(‘http://localhost:3000/cart/‘ + payload.id, {

    1. count: payload.count

    })
    ctx.commit(‘updateCount’, payload)
    }

  4. 提供mutation处理函数

    mutations: {
    …,
    updateCount (state, payload) {

    1. const goods = state.list.find((item) => item.id === payload.id)
    2. goods.count = payload.count

    }
    },

12 综合案例-底部总价展示

  1. 提供getters

    getters: {
    total(state) {

    1. return state.list.reduce((p, c) => p + c.count, 0);

    },
    totalPrice (state) {

    1. return state.list.reduce((p, c) => p + c.count * c.price, 0);

    },
    },

  2. 动态渲染

发表评论

表情:
评论列表 (有 0 条评论,126人围观)

还没有评论,来说两句吧...

相关阅读