Vue(7)

devtools/2025/2/10 23:59:48/

一.Vuex

(1)概述

1.是什么

vuex是一个vue的状态管理工具,状态就是数据,可以帮助管理vue通用的数据(多组件共享的数据)

2.场景

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

3.优势

①共同维护一份数据,数据集中化管理
②响应式变化
③操作简单(提供了辅助函数)

(2)构建vuex[多组件数据共享]环境

效果是三个组件,共享一份数据,任意一个组件都可以修改,三个组件的数据是同步的

<template><div class="box"><h2>Son1 子组件</h2>从vuex中获取的值: <label>{{ $store.state.count }}</label><br><button @click="handleAdd(1)">值 + 1</button><button @click="handleAdd(5)">值 + 5</button><button @click="handleAdd(10)">值 + 10</button><button @click="handleChange">一秒后修改成666</button><button @click="changeFn">改标题</button><hr><!-- 计算属性getters --><div>{{ $store.state.list }}</div><div>{{ $store.getters.filterList }}</div><hr><!-- 测试访问模块中的state - 原生 --><div>{{ $store.state.user.userInfo.name }}</div><button @click="updateUser">更新个人信息</button><button @click="updateUser2">一秒后更新信息</button><div>{{ $store.state.setting.theme }}</div><button @click="updateTheme">更新主题色</button><hr><!-- 测试访问模块中的getters - 原生 --><div>{{ $store.getters['user/UpperCaseName'] }}</div></div>
</template><script>
export default {name: 'Son1Com',created () {console.log(this.$store.getters)},methods: {updateUser () {// $store.commit('模块名/mutation名', 额外传参)this.$store.commit('user/setUser', {name: 'xiaowang',age: 25})},updateUser2 () {// 调用action dispatchthis.$store.dispatch('user/setUserSecond', {name: 'xiaohong',age: 28})},updateTheme () {this.$store.commit('setting/setTheme', 'pink')},handleAdd (n) {// 错误代码(vue默认不会监测,监测需要成本)// this.$store.state.count++// console.log(this.$store.state.count)// 应该通过 mutation 核心概念,进行修改数据// 需要提交调用mutation// this.$store.commit('addCount')// console.log(n)// 调用带参数的mutation函数this.$store.commit('addCount', {count: n,msg: '哈哈'})},changeFn () {this.$store.commit('changeTitle', '传智教育')},handleChange () {// 调用action// this.$store.dispatch('action名字', 额外参数)this.$store.dispatch('changeCountAction', 666)}}
}
</script><style lang="css" scoped>
.box{border: 3px solid #ccc;width: 400px;padding: 10px;margin: 20px;
}
h2 {margin-top: 10px;
}
</style>
<template><div id="app"><h1>根组件- {{ title }}- {{ count }}</h1><input :value="count" @input="handleInput" type="text"><Son1></Son1><hr><Son2></Son2></div>
</template><script>
import Son1 from './components/Son1.vue'
import Son2 from './components/Son2.vue'
import { mapState } from 'vuex'
// console.log(mapState(['count', 'title']))export default {name: 'app',created () {// console.log(this.$router) // 没配console.log(this.$store.state.count)},computed: {...mapState(['count', 'title'])},data: function () {return {}},methods: {handleInput (e) {// 1. 实时获取输入框的值const num = +e.target.value// 2. 提交mutation,调用mutation函数this.$store.commit('changeCount', num)}},components: {Son1,Son2}
}
</script><style>
#app {width: 600px;margin: 20px auto;border: 3px solid #ccc;border-radius: 3px;padding: 10px;
}
</style>

二.创建一个空仓库

1.yarn add vuex@3
安装vuex → 新建vuex模块文件 → 创建仓库 → main . js导入挂载
2.新建store / index . js专门存放vuex
在这里插入图片描述
3.Vue . use(Vuex)创建仓库 new Vuex . store()
4.在main . js中导入挂载到Vue实例上

三.核心概念 - state状态

1.提供数据:
State提供唯一的公共数据源,所有共享的数据都要统一放在Store中的State中存储,在state对象中可以添加我们要共享的数据

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

2.使用数据
①通过store直接访问
②通过辅助函数(简化)
import { mapState } from ‘vuex’
在这里插入图片描述

{{ count}}
//把state中的数据,定义在组件内的计算属性中
computed:{count () {return this.$store.state.count}
}

四.核心概念 - mutations状态

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

// 通过 mutations 可以提供修改数据的方法mutations: {// 所有mutation函数,第一个参数,都是 state// 注意点:mutation参数有且只能有一个,如果需要多个参数,包装成一个对象// 错误代码(vue默认不会监测,监测需要成本)// this.$store.state.count++// console.log(this.$store.state.count)// 应该通过 mutation 核心概念,进行修改数据addCount (state, obj) {console.log(obj)// 修改数据state.count += obj.count},subCount (state, n) {state.count -= n},changeCount (state, newCount) {state.count = newCount},changeTitle (state, newTitle) {state.title = newTitle}},

2.组件中提交调用mutations

 // 需要提交调用mutationthis.$store.commit('addCount')

(1)mutations传参语法

1.提交mutation函数(带参数 - 提交载荷payload)

mutations: {...addCount (state, n) {state.count += n},

2.页面中提交调用mutation

this.$store.commit('addCount',10)

(2)练习


```css
<template><div class="box"><h2>Son2 子组件</h2>从vuex中获取的值:<label>{{ count }}</label><br /><button @click="subCount(1)">值 - 1</button><button @click="subCount(5)">值 - 5</button><button @click="subCount(10)">值 - 10</button><button @click="changeCountAction(888)">1秒后改成888</button><button @click="changeTitle('前端程序员')">改标题</button><hr><div>{{ filterList }}</div><hr><!-- 访问模块中的state --><div>{{ user.userInfo.name }}</div><div>{{ setting.theme }}</div><hr><!-- 访问模块中的state --><div>user模块的数据:{{ userInfo }}</div><button @click="setUser({ name: 'xiaoli', age: 80 })">更新个人信息</button><button @click="setUserSecond({ name: 'xiaoli', age: 80 })">一秒后更新信息</button><div>setting模块的数据:{{ theme }} - {{ desc }}</div><button @click="setTheme('skyblue')">更新主题</button><hr><!-- 访问模块中的getters --><div>{{ UpperCaseName }}</div></div>
</template><script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {name: 'Son2Com',computed: {// mapState 和 mapGetters 都是映射属性...mapState(['count', 'user', 'setting']),...mapState('user', ['userInfo']),...mapState('setting', ['theme', 'desc']),...mapGetters(['filterList']),...mapGetters('user', ['UpperCaseName'])},methods: {// mapMutations 和 mapActions 都是映射方法// 全局级别的映射...mapMutations(['subCount', 'changeTitle']),...mapActions(['changeCountAction']),// 分模块的映射...mapMutations('setting', ['setTheme']),...mapMutations('user', ['setUser']),...mapActions('user', ['setUserSecond'])// handleSub (n) {//   this.subCount(n)// }}
}
</script><style lang="css" scoped>
.box {border: 3px solid #ccc;width: 400px;padding: 10px;margin: 20px;
}
h2 {margin-top: 10px;
}
</style>

(3)辅助函数:mapMutations

mapMutations和mapState很像,它是把位于Mutations中的方法提取出来,映射到组件methods中

subCount (state, n) {state.count -= n},
import { mapMutations } from 'vuex'methods:{...mapMutations(['subCount']),
}
 methods: {subCount(n){this.$store.commit('subCount', n)}}

五.核心概念 - actions

说明:mutations必须是同步的(便于检测数据变化,记录调式)

mutations: {changeCount (state, newCount) {state.count = newCount},

1.提供action方法

  actions: {setAsynCount (context, num) {// 一秒后,给一个数,去修改numsetTimeout(() => {context.commit('changeCount', num)}, 1000)}},

2.页面中dispatch调用

this.$store.dispatch('setAsyncCount',200)

辅助函数 - mapActions

maoActions是把位于actions中的方法提取出来,映射到组件methods中

 actions: {// context 上下文 (此处未分模块,可以当成store仓库)// context.commit('mutation名字', 额外参数)changeCountAction (context, num) {// 这里是setTimeout模拟异步,以后大部分场景是发请求setTimeout(() => {context.commit('changeCount', num)}, 1000)}},
import {  mapActions } from 'vuex'methods: {...mapActions(['changeCountAction']),}
methods:{changeCountAction(n){this.$store.dispatch('changeCountAction',n)},
}

六.核心概念 - getters

说明:从state中派生出一些状态,这些状态是依赖state,此时会用到getters
1.定义getters

getters: {// 注意点:// 1. 形参第一个参数,就是state// 2. 必须有返回值,返回值就是getters的值filterList (state) {return state.list.filter(item => item > 5)}},

2.访问getters
①通过store访问getters{{ $store.getters.filterList }}
②通过辅助函数mapGetters映射

computed:{...mapGetters(['filterList'])
},

七.核心概念 - 模块module(进阶语法)

由于vuex使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿,变得难以维护
在这里插入图片描述
模块拆分:store/modules/user.js

// user模块
const state = {userInfo: {name: 'zs',age: 18},score: 80
}
const mutations = { }
const actions = {}
const getters = {}
export default {namespaced: true,state,mutations,actions,getters
}

尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的state中,属性名就是模块名
使用模块总的数据:
①直接通过模块名访问$store.state.模块名.xxx
②通过mapState(‘模块名’,[‘xxx’]),需要开启命名空间

export default {namespaced: true
}
// user模块
const state = {userInfo: {name: 'zs',age: 18},score: 80
}
const mutations = {setUser (state, newUserInfo) {state.userInfo = newUserInfo}
}
const actions = {setUserSecond (context, newUserInfo) {// 将异步在action中进行封装setTimeout(() => {// 调用mutation   context上下文,默认提交的就是自己模块的action和mutationcontext.commit('setUser', newUserInfo)}, 1000)}
}
const getters = {// 分模块后,state指代子模块的stateUpperCaseName (state) {return state.userInfo.name.toUpperCase()}
}export default {namespaced: true,state,mutations,actions,getters
}

购物车案例

cart-footer

<template><div class="footer-container"><!-- 中间的合计 --><div><span>共 {{ total }} 件商品,合计:</span><span class="price">¥{{ totalPrice }}</span></div><!-- 右侧结算按钮 --><button class="btn btn-success btn-settle">结算</button></div>
</template><script>
import { mapGetters } from 'vuex'
export default {name: 'CartFooter',computed: {...mapGetters('cart', ['total', 'totalPrice'])}
}
</script><style lang="less" scoped>
.footer-container {background-color: white;height: 50px;border-top: 1px solid #f8f8f8;display: flex;justify-content: flex-end;align-items: center;padding: 0 10px;position: fixed;bottom: 0;left: 0;width: 100%;z-index: 999;
}.price {color: red;font-size: 13px;font-weight: bold;margin-right: 10px;
}.btn-settle {height: 30px;min-width: 80px;margin-right: 20px;border-radius: 20px;background: #42b983;border: none;color: white;
}
</style>

cart-header

<template><div class="header-container">购物车案例</div>
</template><script>
export default {name: 'CartHeader'
}
</script><style lang="less" scoped>
.header-container {height: 50px;line-height: 50px;font-size: 16px;background-color: #42b983;text-align: center;color: white;position: fixed;top: 0;left: 0;width: 100%;z-index: 999;
}
</style>

cart-item

<template><div class="goods-container"><!-- 左侧图片区域 --><div class="left"><img :src="item.thumb" class="avatar" alt=""></div><!-- 右侧商品区域 --><div class="right"><!-- 标题 --><div class="title">{{ item.name }}</div><div class="info"><!-- 单价 --><span class="price">¥{{ item.price }}</span><div class="btns"><!-- 按钮区域 --><button class="btn btn-light" @click="btnClick(-1)">-</button><span class="count">{{ item.count }}</span><button class="btn btn-light" @click="btnClick(1)">+</button></div></div></div></div>
</template><script>
export default {name: 'CartItem',methods: {btnClick (step) {const newCount = this.item.count + stepconst id = this.item.idif (newCount < 1) returnthis.$store.dispatch('cart/updateCountAsync', {id,newCount})}},props: {item: {type: Object,required: true}}
}
</script><style lang="less" scoped>
.goods-container {display: flex;padding: 10px;+ .goods-container {border-top: 1px solid #f8f8f8;}.left {.avatar {width: 100px;height: 100px;}margin-right: 10px;}.right {display: flex;flex-direction: column;justify-content: space-between;flex: 1;.title {font-weight: bold;}.info {display: flex;justify-content: space-between;align-items: center;.price {color: red;font-weight: bold;}.btns {.count {display: inline-block;width: 30px;text-align: center;}}}}
}.custom-control-label::before,
.custom-control-label::after {top: 3.6rem;
}
</style>

cart

import axios from 'axios'
export default {namespaced: true,state () {return {// 购物车数据 [{}, {}]list: []}},mutations: {updateList (state, newList) {state.list = newList},// obj: { id: xxx, newCount: xxx }updateCount (state, obj) {// 根据 id 找到对应的对象,更新count属性即可const goods = state.list.find(item => item.id === obj.id)goods.count = obj.newCount}},actions: {// 请求方式:get// 请求地址:http://localhost:3000/cartasync getList (context) {const res = await axios.get('http://localhost:3000/cart')context.commit('updateList', res.data)},// 请求方式:patch// 请求地址:http://localhost:3000/cart/:id值  表示修改的是哪个对象// 请求参数:// {//   name: '新值',  【可选】//   price: '新值', 【可选】//   count: '新值', 【可选】//   thumb: '新值'  【可选】// }async updateCountAsync (context, obj) {// 将修改更新同步到后台服务器await axios.patch(`http://localhost:3000/cart/${obj.id}`, {count: obj.newCount})// 将修改更新同步到 vuexcontext.commit('updateCount', {id: obj.id,newCount: obj.newCount})}},getters: {// 商品总数量 累加counttotal (state) {return state.list.reduce((sum, item) => sum + item.count, 0)},// 商品总价格 累加count * pricetotalPrice (state) {return state.list.reduce((sum, item) => sum + item.count * item.price, 0)}}
}

app

<template><div class="app-container"><!-- Header 区域 --><cart-header></cart-header><!-- 商品 Item 项组件 --><cart-item v-for="item in list" :key="item.id" :item="item"></cart-item><!-- Foote 区域 --><cart-footer></cart-footer></div>
</template><script>
import CartHeader from '@/components/cart-header.vue'
import CartFooter from '@/components/cart-footer.vue'
import CartItem from '@/components/cart-item.vue'import { mapState } from 'vuex'export default {name: 'App',created () {this.$store.dispatch('cart/getList')},computed: {...mapState('cart', ['list'])},components: {CartHeader,CartFooter,CartItem}
}
</script><style lang="less" scoped>
.app-container {padding: 50px 0;font-size: 14px;
}
</style>

http://www.ppmy.cn/devtools/157767.html

相关文章

CSS 相关知识

1、高度已知&#xff0c;三栏布局&#xff0c;左右宽度 200&#xff0c;中间自适应&#xff0c;如何实现&#xff1f; <body><div class"box"><div class"box1">高度已知</div><div class"box2">左右宽度 200&…

Redis 事务的介绍

1. Redis 事务介绍 Redis 的事务和 MySQL 的事务概念上是类似的&#xff0c;不过也有一定区别&#xff1a; 弱化的原子性&#xff1a;Redis 没有 “回滚机制”&#xff0c;只能批量执行操作&#xff0c;但如果其中一个操作失败&#xff0c;不会恢复到初始状态。不保证一致性&a…

构建高效Facebook广告矩阵:精准营销与广告投放的全新策略

随着社交媒体广告成为企业营销不可或缺的一部分&#xff0c;Facebook作为全球最大的社交平台之一&#xff0c;已成为企业营销的重要阵地。在Facebook上成功的广告投放&#xff0c;往往不只是依赖于单一广告&#xff0c;而是通过构建一个精准的广告矩阵来提升品牌曝光、增强用户…

Rust 核心语法总结

一、Rust 核心语法总结 1. 基础语法 变量绑定 let x = 5; // 不可变绑定 let mut y = 10; // 可变绑定数据类型 标量类型:i32, u32, f64, bool, char复合类型:元组 (i32, f64)、数组 [i32; 5]字符串:String(堆分配)、&str(切片)所有权系统 所有权规则…

基于RK3588/RK3576+FPGA的巡检机器人六自由度机械臂的系统设计

当今巡检机器人机械臂在管廊隧道等复杂环境的作业过程中&#xff0c;经常面临空间狭窄 且障碍物密集的问题&#xff0c;这就要求机械臂具备在狭窄空间进行避障路径规划的能力。此 外&#xff0c;一些不确定性因素如在突发或异常环境条件下&#xff0c;机械臂的全局状态信息感知…

4.2 检查k8s集群准入配置和其他准备工作

本节重点总结 : k8s集群检查操作新建项目 kube-mutating-webhook-inject-pod&#xff0c;准备工作 k8s集群检查操作 检查k8s集群否启用了准入注册 API&#xff1a; 执行kubectl api-versions |grep admission如果有下面的结果说明已启用 kubectl api-versions |grep admiss…

基于SpringBoot的校园社交平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

芯科科技的BG22L和BG24L带来应用优化的超低功耗蓝牙®连接

全新的BG22L为常见蓝牙设备提供强大的安全性和处理能力&#xff0c;而BG24L支持先进的AI/ML加速和信道探测功能 2025年2月6日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#x…