[vue2]深入理解vuex

本节内容

  • 概述
  • 初始化仓库
  • 定义数据
  • 访问数据
  • 修改数据
  • 处理异步
  • 派生数据
  • 模块拆分
  • 案例-购物车

概述

vuex是一个vue的状态管理工具, 状态就是数据

场景

  1. 某个状态在很多个组件使用 (个人信息)
  2. 多个组件 共同维护 一份数据 (购物车)

优势

  1. 数据集中式管理
  2. 数据响应式变化

初始化仓库

  1. 安装vuex: yarn add vuex@3
  2. 创建仓库
// 这里面存放的就是 vuex 相关的核心代码
import Vue from 'vue'
import Vuex from 'vuex'// 插件安装
Vue.use(Vuex)// 创建仓库
const store = new Vuex.Store({ })// 导出给main.js使用
export default store
  1. 挂载仓库
... ...
import store from '@/store/index'// 挂载仓库
new Vue({render: h => h(App),store
}).$mount('#app')

定义数据

stata提供唯一的公共数据源, 所有共享的数据都要统一放在store的state中存储

... ...
// 创建仓库
const store = new Vuex.Store({// 严格模式 (有利于初学者,检测不规范的代码 => 上线时需要关闭)strict: true,// 通过 state 可以提供数据 (所有组件共享的数据)state: {title: '仓库大标题',count: 100,list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}})

访问数据

1>通过store访问数据

  • 获取store
    • this.$store
    • import 导入 store
  • 使用store
    • 模版中: {{ $store.state.xxx }}
    • 组件逻辑中: this.$store.state.xxx
    • JS模块中: store.state.xxx

2>通过辅助函数访问数据

mapState是辅助函数, 帮助我们把store中的数据 自动映射 到组件的计算属性中

  • 导入函数: import { mapState } from 'vuex'
  • 映射数据: computed: { ...mapState(['count']) }
  • 使用数据: this.count
  • 辅助函数的本质就是把state中的数据定义在计算属性中, 方便使用

修改数据

vuex同样遵循单向数据流, 组件中不能直接修改仓库数据, 而是提交申请后, 由仓库修改

默认情况, 直接修改数据也不会报错, 因为额外监控损失性能, 通过 strict: true 可以开启严格模式, 监控错误语法

state数据的修改只能通过mutations

1>定义mutations方法

定义mutations对象, 对象中存放修改state的方法

... ...
const store = new Vuex.Store({state: {count: 100,},// 通过 mutations 可以提供修改数据的方法mutations: {// 所有mutation函数,第一个参数都是 stateaddCount (state, n) {// 修改数据state.count += n},},
})
  1. 组件中提交commit调用mutations
  2. 语法: this.$store.commit('addCount', 10 )
  3. mutation函数的参数也叫载荷, 触发mutations传参也叫提交载荷(payload)
  4. 注意: mutation提交参数有且只能有一个,如果需要多个参数,包装成一个对象

2>通过辅助函数修改数据

mapMutations辅助函数, 可以把mutations中的方法提取出来, 映射到methods中, 更方便的使用

  • 导入函数: import { mapMutations } from 'vuex'
  • 映射方法: methods: { ...mapMutations(['subCount']) }
  • 使用方法: this.subCount(10)
  • 辅助函数的本质就是把mutations中的方法映射在methods中, 方便使用

3>输入框双向绑定

仓库的数据要遵循单向数据流, 所以输入框 绑定仓库数据 不能使用v-model

<template><div id="app"><h1> 根组件 - {{ count }} </h1><!-- 3, 使用:value绑定仓库的值 --><input :value="count" @input="handleInput" type="text"></div>
</template><script>
import { mapState } from 'vuex'export default {name: 'app',computed: {...mapState(['count'])},methods: {handleInput (e) {// 1. 实时获取输入框的值const num = +e.target.value// 2. 提交mutation,调用mutation函数this.$store.commit('changeCount', num)}},
}
</script>
const store = new Vuex.Store({strict: true,state: {count: 100,},mutations: {// 更新 count 数据的方法changeCount (state, newCount) {state.count = newCount},},
})

处理异步

mutations必须是同步的(便于监测数据变化, 记录调试), 需要提供 actions 方法, 处理异步的相关逻辑

  1. 定义action方法, 处理异步的逻辑
const store = new Vuex.Store({strict: true,state: {count: 100,},mutations: {changeCount (state, newCount) {state.count = newCount},},// actions 处理异步// 注意:不能直接操作 state,操作 state,还是需要 commit mutationactions: {// context上下文 (未分模块,当成store仓库, 分模块后, 当成所在模块)// context.commit('mutation名字', 额外参数)changeCountAction (context, num) {// 这里是setTimeout模拟异步,以后大部分场景是发请求setTimeout(() => {context.commit('changeCount', num)}, 1000)}},
})
  1. 直接dispatch调用
<template><div class="box"><button @click="handleChange">一秒后修改成666</button></div>
</template><script>
export default {methods: {handleChange () {this.$store.dispatch('changeCountAction', 200)}}
}
</script>
  1. mapActions 辅助函数调用
<template><div class="box"><button @click="handleChange">一秒后修改成666</button></div>
</template><script>
import { mapActions } from 'vuex'
export default {methods: {...mapActions(['changeCountAction']),change () {this.changeCountAction('100')}}
}
</script>
  1. 辅助函数的本质是把actions中的方法映射到组件methods中, 方便调用

派生数据

有时需要基于state 派生出一些数据, 这些数据依赖state, 就可以使用getters

1, 定义getters方法

const store = new Vuex.Store({strict: true,state: {list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]},// 4. getters 类似于计算属性getters: {// 注意点:// 1. 形参第一个参数,就是state// 2. 必须有返回值,返回值就是getters的值filterList (state) {return state.list.filter(item => item > 5)}},
})

2, 访问getters数据

3, 在getters中访问getters

export default {namespaced: true,state () {return {cartList: []}},getters: {// 选中的商品selCartList (state) {return state.cartList.filter(item => item.isChecked)},// 选中的商品总数selCount (stat, getterse) {// 注意:// 可以在getters中,通过第二个参数, 拿到其他gettersreturn getterse.selCartList.reduce((sum, item) => sum + item.goods_num, 0)},}
}

模块拆分

由于vuex使用单一状态树, 应用的所有状态都会集中到一个大的对象, 当应用复杂时, store对象就会相当臃肿

步骤

  1. 新建子模块
// user模块
const state = {userInfo: {name: 'zs',age: 18},score: 80
}
const mutations = { }
const actions = { }
const getters = { }export default {state,mutations,actions,getters
}
  1. 挂载子模块
// 1,引入子模块
import user from './modules/user'const store = new Vuex.Store({... ...// 2. 通过modules挂载子模块modules: {user,}
})
  1. 检测: 查看调试工具

开启命名空间

子模块开启命名名后, 每个子模块之间相互隔离, 访问子模块数据时, 会更加清晰

export default {// 开启子模块命名空间// 好处:数据独立,更加清晰namespaced: true,state,mutations,actions,getters
}

访问子模块数据

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

  1. 直接通过模块名访问
  • $store.state.模块名.xxx
  1. 通过mapState映射数据
  • 不开启命名空间: mapState(['xxx'])
  • 开启命名空间: mapState('模块名', ['xxx']) (推荐)

修改子模块数据

mutation会被挂载到全局, 需要开启命名空间, 才会挂载到子模块

  1. 直接通过store访问
  • $store.commit('模块名/xxx', 额外参数)
  1. 通过mapMutations映射
  • 不开启命名空间: mapMutations(['xxx'])
  • 开启命名空间: mapMutations('模块名', ['xxx']) (推荐)

异步修改子模块数据

action会被挂载到全局, 需要开启命名空间, 才会挂载到子模块

  1. 直接通过store访问
  • $store.dispatch('模块名/xxx', 额外参数)
  1. 通过mapActions映射
  • 不开启命名空间: mapActions(['xxx'])
  • 开启命名空间: mapActions('模块名', ['xxx']) (推荐)

访问子模块getters

  1. 直接通过模块名访问
  • $store.store.getters['模块名/xxx']
  1. 通过mapGetters映射
  • 不开启命名空间: mapGetters(['xxx'])
  • 开启命名空间: mapGetters('模块名', ['xxx']) (推荐)

跨模块调用mutations

export default {namespaced: true,state () {return {// 个人权证相关userInfo: getInfo()}},mutations: {// 设置用户信息SET_USER_INFO (state, userInfo) {state.userInfo = userInfosetInfo(userInfo) // 存储用户信息到本地}},actions: {// 退出登录logout ({ commit }) {// 清空个人信息commit('SET_USER_INFO', {})// 情况购物车信息(跨模块调用mutations)// commit('模块名/方法名', 传值/null, { root: true(开启全局) })commit('cart/setCartList', [], { root: true })}},getters: {}
}

案例-购物车

效果展示

功能分析

  1. 请求动态渲染购物车, 数据存veux
  2. 数据框控件 修改数据
  3. 动态计算总价和总数量

搭建环境

通过脚手架新建项目, 清空src文件夹, 替换准备好的素材

mock数据

基于 json-server 工具, 模拟后端接口服务

  1. 官网: json-server - npm
    1. 全局安装: npm install json-server -g
  1. 代码根目录新建db文件夹
  2. 准备index.json文件, 放入db目录
  3. 进入db目录, 执行命令启动接口服务: json-server index.json
  4. 访问接口测试: http://localhost:3000/cart

创建cart模块

export default {// 开启命名空间namespaced: true,// 分模块存储, 官方建议使用函数方式提供数据state () {return {list: []}}
}
import cart from './modules/cart'export default new Vuex.Store({modules: {cart}
})

请求数据渲染

import axios from 'axios'
export default {// 开启命名空间namespaced: true,// 数据源state () {return {list: []}},mutations: {// 同步更新数据updataList (state, list) {state.list = list}},actions: {// 异步请求数据async getList (context) {const res = await axios.get('http://localhost:3000/cart')context.commit('updataList', res.data)}},getters: {}
}
<template><div class="app-container">... ...<!-- 商品 Item 项组件 --><cart-item v-for="item in list" :key="item.id" :item="item"></cart-item>... ...</div>
</template><script>
import { mapState } from 'vuex'export default {name: 'App',created () {// 触发异步请求this.$store.dispatch('cart/getList')},computed: {// 映射仓库数据...mapState('cart', ['list'])}
}
</script>

修改数量

import axios from 'axios'
export default {// 开启命名空间namespaced: true,// 数据源state () {return {list: []}},mutations: {updataItem (state, obj) {const goods = state.list.find(item => item.id === obj.id)goods.count = obj.newNnm}},actions: {async updateList (context, obj) {// 修改后台数据const res = await axios.get(`http://localhost:3000/cart/${obj.id}`, {count: obj.newNnm})// 更新仓库数据context.commit('updataItem', obj)}},
}
<template><div class="goods-container">...<div class="btns"><!-- 按钮区域 --><button class="btn btn-light" @click="changNum(-1)">-</button><span class="count">{{ item.count }}</span><button class="btn btn-light" @click="changNum(1)">+</button></div>...</div>
</template><script>
export default {name: 'CartItem',props: {item: {type: Object,required: true}},methods: {changNum (n) {const newNnm = this.item.count + nconst id = this.item.idif (newNnm === 0) returnthis.$store.dispatch('cart/updateList', { id, newNnm })}}
}
</script>

计算底部数据

export default {... ...getters: {total (state) {return state.list.reduce((sum, item) => sum + item.count, 0)},totalPrice (state) {return state.list.reduce((sum, item) => sum + item.count * item.price, 0)}}
}
<template><div class="footer-container"><!-- 中间的合计 --><div><span>共 {{ total }} 件商品,合计:</span><span class="price">¥{{ totalPrice }}</span></div>... ...</div>
</template><script>
import { mapGetters } from 'vuex'
export default {name: 'CartFooter',computed: {...mapGetters('cart', ['total', 'totalPrice'])}
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27084.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue36-组件化编程的概念

一、组件化编程VS传统编程 1-1、传统方式的编写应用 存在的问题&#xff1a; 1-2、组件方式的编写应用 注意&#xff1a;是引入&#xff0c;不是复制&#xff01; 体现了封装的概念&#xff01; 二、模块化、组件化

SonarQube安全扫描常见问题

目录 一、SonarQube质量报告 二、SonarQube扫描常见问题和修复方法 三、SonarQube质量配置 最近小编在使用SonarQube工具进行代码扫描&#xff0c;检查代码异味&#xff0c;系统漏洞等&#xff0c;实际过程中也遇到了不少问题&#xff0c;这篇文章主要列举我遇到的常见问题和…

Android Jetpack Compose 实现一个电视剧选集界面

文章目录 需求概述效果展示实现思路代码实现总结 需求概述 我们经常能看到爱奇艺或者腾讯视频这类的视频APP在看电视剧的时候都会有一个选集的功能。如下图所示 这个功能其实很简单&#xff0c;就是绘制一些方块&#xff0c;在上面绘制上数字&#xff0c;还有标签啥的。当用户…

流程与IT双驱动:锐捷网络如何构建持续领先的服务竞争力?

AI大模型及相关应用进入“竞赛时代”&#xff0c;算力作为关键要素备受关注&#xff0c;由于算力行业对网络设备和性能有较大需求&#xff0c;其发展也在推动ICT解决方案提供商加速升级&#xff0c;提升服务响应速度和服务质量。 锐捷网络是行业领先的ICT基础设施及行业解决方…

Spark groupByKey和reduceByKey对比

在 Apache Spark 中&#xff0c;groupByKey 和 reduceByKey 都是用于对键值对 (key-value) 数据集进行分组和聚合的操作。然而&#xff0c;它们在性能和使用场景上有显著的差异。 groupByKey 函数 groupByKey 将数据集中的所有键相同的值进行分组&#xff0c;然后返回一个键值…

Error:Kotlin: Module was compiled with an incompatible version of Kotlin.

一、问题&#xff1a;运行spring boot项目时&#xff0c;idea报出错误&#xff1a;时提示报错如下图&#xff1a; 错误代码&#xff1a; Error:Kotlin: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected …

未来AI大模型的发展趋势

大家好&#xff0c;我是小悟 未来AI大模型的发展趋势无疑将是多元化、高效化、普及化以及人性化。随着技术的飞速进步&#xff0c;AI大模型将在各个领域中展现出更加广泛和深入的应用&#xff0c;成为推动社会进步的重要力量。 多元化是AI大模型发展的重要方向。随着数据量的…

FastAPI系列 4 -路由管理APIRouter

FastAPI系列 -路由管理APIRouter 文章目录 FastAPI系列 -路由管理APIRouter一、前言二、APIRouter使用示例1、功能拆分2、users、books模块开发3、FastAPI主体 三、运行结果 一、前言 未来的py开发者请上座&#xff0c;在使用python做为后端开发一个应用程序或 Web API&#x…

java:使用JSqlParser给sql语句增加tenant_id和deleted条件

# 示例代码 【pom.xml】 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-core</artifactId><version>3.4.3.1</version> </dependency>【MyJSqlParserTest.java】 package com.chz.myJSqlParser;pu…

请求headers处理

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 有时在请求一个网页内容时&#xff0c;发现无论通过GET或者是POST以及其他请求方式&#xff0c;都会出现403错误。产生这种错误是由于该网页为了防止…

phpStudy里面的MySQL启动不了

C:\Users\Administrator>netstat -an | find "3306" TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING TCP 0.0.0.0:33060 0.0.0.0:0 LISTENING TCP [::]:3306 [::]:0 LISTENING TCP [::]:33060 [::]:0 LISTENING 从你提供的输出结果可以看到&#xff0c;端口3306和33060已经…

python中的turtle

turtle个别指令 初始箭头默认指向为东&#xff08;右&#xff09; 往前&#xff08;右&#xff09;三个格&#xff1a;turtle.forward(3) 往后&#xff08;左&#xff09;三个格&#xff1a;turtle.backward(3) 往左转90度&#xff1a;turtle.left(90) 往右转90度&#xf…

r语言数据分析案例25-基于向量自回归模型的标准普尔 500 指数长期预测与机制分析

一、背景介绍 2007 年的全球经济危机深刻改变了世界经济格局&#xff0c;引发了一系列连锁反应&#xff0c;波及各大洲。经济增长停滞不前&#xff0c;甚至在某些情况下出现负增长&#xff0c;给出口导向型发展中国家带来了不确定性。实体经济受到的冲击尤为严重&#xff0c;生…

ATFX汇市:日本央行维持0.1%利率不变,植田和男发言偏鹰

ATFX汇市&#xff1a;北京时间11:25&#xff0c;日本央行公布6月利率决议结果&#xff0c;宣布维持0~0.1%的基准利率区间不变&#xff0c;此前市场预期其将再次加息。消息公布后&#xff0c;USDJPY的5分钟内从157.09上涨至157.70&#xff0c;涨幅61基点。25分钟之后&#xff0c…

Ollama在MacOS、Linux本地部署千问大模型及实现WEB UI访问

一、前言 阿里通义千问发布了Qwen2&#xff0c;提供了0.5B&#xff5e;72B的量级模型&#xff0c;在​​Ollama官网​​可以搜索qwen2查看&#xff0c;本文提供了Ollama的下载&#xff08;在线/离线安装&#xff09;、Ollama运行模型、使用WebUI连接模型以及页面简单配置。 …

Leetcode刷题笔记10

14. 最长公共前缀 14. 最长公共前缀 - 力扣&#xff08;LeetCode&#xff09; 首先&#xff0c;检查边界条件 如果输入的字符串数组为空&#xff0c;直接返回空字符串。 然后使用minmax_element函数找到数组中字典序最小和最大的字符串。 因为公共前缀一定会出现在字典序最…

c++实战知识点

c实战知识点 一、概述1.数据2.C11的原始字面量3.数据类型的别名4.const修饰指针5.void关键字6.内存模型7.二级指针8.函数指针和回调函数9.数组10.C风格字符串11.二维数组用于函数的参数行指针&#xff08;数组指针&#xff09; 12.引用引用与const 13.各种形参的使用场景14.重载…

Parallels Desktop for Mac 19.4.0 (build 54570) - 在 Mac 上运行 Windows

Parallels Desktop for Mac 19.4.0 (build 54570) - 在 Mac 上运行 Windows Parallels Desktop 19 请访问原文链接&#xff1a;Parallels Desktop for Mac 19.4.0 (build 54570) - 在 Mac 上运行 Windows&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者…

Linux 基本指令2

cp 指令 cp[选项]源文件 目标文件 将源文件的内容复制到目标文件中&#xff0c;源文件可以有多个&#xff0c;最后一个文件为目标文件&#xff0c;目标文件也可以是一段路径&#xff0c;若目的地不是一个目录的话会拷贝失败。若没有路径上的目录则会新建一个&#xff0c;若源是…