Vuex(二) —— 用Vuex完成购物车案例
目录
- 需求
- 需求分析
- 组件分析
- 组件通信
- 开发
- 准备环境
- 准备模块结构
- 商品列表组件
- 展示商品列表
- 添加购物车
- 我的购物车组件
- 购物车列表
- 商品数量和统计功能
- 删除购物车商品
- 购物车列表组件
- 购物车列表
- 全选操作
- 数字加减并统计小计
- 删除功能
- 统计总数量和总钱数
- 处理金额小数的问题
- 本地存储
- 完整案例
上一节介绍了Vuex
的核心原理及简单使用,这里来一个实际案例
需求
- 商品列表展示商品、价格和【加入购物车】按钮
- 点击【加入购物车】按钮加入购物车,【我的购物车】提示数量增加
- 【我的购物车】按钮
- 鼠标悬停出现
popover
,展示购物车里面的商品,价格数量,【删除】按钮,还有总数量和总价格,还有【去购物车】按钮 - 【删除】按钮可以删除整个商品,总价和数量都会改变
- 点击【去购物车】按钮可以跳到购物车界面
- 鼠标悬停出现
- 展示多选框,商品,单价,数量及【加减按钮车】,小计,【删除】按钮,总量和总价,【结算】按钮
- 数量加减改变数量,小计,总数量和总价
- 【删除】按钮删除整个商品
- 多选框不选中的不计入总数量和总价格。
- 刷新页面,状态还在,存在本地存储中
需求分析
组件分析
- 路由组件
- 商品列表(①)
- 购物车列表(②)
- 我的购物车弹框组件(③)
组件通信
②和③都依赖购物车的数据,①中点击添加购物车,主要把数据传递给②和③,②和③之间的数据修改也互相依赖,如果没有Vuex
需要花时间精力在如何在组件中传值上。
开发
准备环境
- 下载模板vuex-cart-demo-template,里面已经将路由组件、样式组件和数据都写好了,我们只要负责实现功能即可。项目中还有一个
server.js
的文件,这个是node
用来模拟接口的。
const _products = [{ id: 1, title: 'iPad Pro', price: 500.01 },{ id: 2, title: 'H&M T-Shirt White', price: 10.99 },{ id: 3, title: 'Charli XCX - Sucker CD', price: 19.99 }
]app.use(express.json())
// 模拟商品数据
app.get('/products', (req, res) => {res.status(200).json(_products)
})
// 模拟支付
app.post('/checkout', (req, res) => {res.status(200).json({success: Math.random() > 0.5})
})
- 首先
npm install
安装依赖,之后node server
将接口跑起来,然后再添加终端输入npm run serve
让项目跑起来,这个时候访问http://127.0.0.1:3000/products
可以访问到数据,访问http://localhost:8080/
可以访问到页面
准备模块结构
- 在
store
文件夹中创建modules
文件夹,创建两个模块products.js
和cart.js
- 在
products.js
和cart.js
文件中搭建基本结构
const state = {}
const getters = {}
const mutations = {}
const actions = {}export default {namespaced: true,state,getters,mutations,actions
}
- 在
index.js
中导入并且引用模块
import Vue from 'vue'
import Vuex from 'vuex'
// 1. 导入模块
import products from './modules/products'
import cart from './modules/cart'
Vue.use(Vuex)export default new Vuex.Store({state: {},mutations: {},actions: {},// 2. 引用模块modules: {products,cart}
})
商品列表组件
- 展示商品列表
- 添加购物车
展示商品列表
- 在
products.js
中要实现下面的方法
- 在
state
中定义一个属性记录所有的商品数据- 在
mutations
中添加方法去修改商品数据- 在
actions
中添加方法异步向接口请求数据
// 导入axios
import axios from 'axios'
const state = {// 记录所有商品products: []
}
const getters = {}
const mutations = {// 给products赋值setProducts (state, payLoad) {state.products = payLoad}}
const actions = {// 异步获取商品,第一个是context上下文,解构出来要commitasync getProducts ({ commit }) {// 请求接口const { data } = await axios({method: 'GET',url: 'http://127.0.0.1:3000/products'})// 将获取的数据将结果存储到state中commit('setProducts', data)}
}export default {namespaced: true,state,getters,mutations,actions
}
- 在
products.vue
中将原来的data
删除,导入模块并使用
<script>
// 导入需要的模块
import { mapActions, mapState } from 'vuex'
export default {name: 'ProductList',// 创建计算属性,映射products数据,因为开启了命名空间,这里添加了命名空间的写法,后面是映射的属性productscomputed: {...mapState('products', ['products'])},// 把actions里面的方法映射进来,第一个依旧是命名空间的写法methods: {...mapActions('products', ['getProducts'])},// 组件创建之后调用getProducts获取数据created () {this.getProducts()}
}
</script>
- 打开浏览器,可以看到商品界面已经出现了三个商品。
添加购物车
把当前点击的商品存储到一个位置,将来在购物车列表组件中可以访问到,所以需要一个位置记录所有的购物车数据,这个数据在多个组件中可以共享,所以将这个数据放在cart
模块中
- 在模块
cart.js
中写数据
const state = {// 记录购物车商品数据cartProducts: []
}
const getters = {}
const mutations = {// 第二个是payLoad,传过来的商品对象addToCart (state, product) {// 1. 没有商品时把该商品添加到数组中,并增加count,isChecked,totalPrice// 2. 有该商品时把商品数量加1,选中,计算小计// 判断有没有该商品,返回该商品const prod = state.cartProducts.find(item => item.id === product.id)if (prod) {// 该商品数量+1prod.count++// 选中prod.isChecked = true// 小计 = 数量 * 单价prod.totalPrice = prod.count * prod.price} else {// 给商品列表添加一个新商品state.cartProducts.push({// 原来products的内容...product,// 数量count: 1,// 选中isChecked: true,// 小计为当前单价totalPrice: product.price})}}
}
const actions = {}export default {namespaced: true,state,getters,mutations,actions
}
- 在
products.vue
中导入cart
的添加购物车mutation
<template><div>...<el-table:data="products"style="width: 100%">...<el-table-columnprop="address"label="操作"><!-- 这一行可以通过插槽获取作用域数据 --><!-- <template slot-scope="scope"> 这是2.6之前的写法,2.6之后已经过时了换成下里面的写法了--><template v-slot="scope"><!--添加点击事件,传入当前列表--><el-button @click="addToCart(scope.row)">加入购物车</el-button></template></el-table-column></el-table></div>
</template><script>
import { mapActions, mapMutations, mapState } from 'vuex'
export default {name: 'ProductList',computed: {...mapState('products', ['products'])},methods: {...mapActions('products', ['getProducts']),// 将添加购物商品的数据映射到methods中...mapMutations('cart', ['addToCart'])},created () {this.getProducts()}
}
</script><style></style>
- 点开浏览器,可以点击加入购物车按钮,点开调试台可以看到数据的变化
我的购物车组件
- 购买商品列表
- 统计购物车总数和总价
- 删除按钮
购物车列表
- 在
component/pop-cart.vue
中导入购物车数据
<template><el-popoverwidth="350"trigger="hover"><!-- 这里是cartProducts的数据,不需要修改 --><el-table :data="cartProducts" size="mini"><el-table-column property="title" width="130" label="商品"></el-table-column>...</el-table>...</el-popover>
</template><script>
// 导入vuex模块
import { mapState } from 'vuex'
export default {name: 'PopCart',computed: {// 把cart模块中的cartProducts导入...mapState('cart', ['cartProducts'])}
}
</script><style></style>
- 打开浏览器,点击商品添加购物车,可以看到弹窗里有新加的商品
商品数量和统计功能
- 因为总数和总量可以用
store
中的getters
来写,因为是对数据的简单修改,在cart.js
的getters
中这么写:
const getters = {// 接收state为参数,返回结果totalCount (state) {// 返回数组中某个元素的和,用reduce方法// reduce方法接收两个参数,第一个参数是函数,第二个参数是起始数(这里从0开始)// 函数内部接收两个参数,第一个参数是求和变量,第二个数组的元素return state.cartProducts.reduce((sum, prod) => sum + prod.count, 0)},// 与上面同样写法totalPrice () {return state.cartProducts.reduce((sum, prod) => sum + prod.totalPrice, 0)}
}
- 在
components/pop-cart.vue
中引用
<template><el-popoverwidth="350"trigger="hover">...<div><!-- 总数和总量也改成插值表达式 --><p>共 {{ totalCount }} 件商品 共计¥{{ totalPrice }}</p><el-button size="mini" type="danger" @click="$router.push({ name: 'cart' })">去购物车</el-button></div><!-- 徽章这里,将value修改成totalCount --><el-badge :value="totalCount" class="item" slot="reference"><el-button type="primary">我的购物车</el-button></el-badge></el-popover>
</template><script>
// 把mapGetters导入
import { mapGetters, mapState } from 'vuex'
export default {name: 'PopCart',computed: {...mapState('cart', ['cartProducts']),// 把cart模块中的totalCount和totalPrice导入...mapGetters('cart', ['totalCount', 'totalPrice'])}
}
</script><style></style>
- 打开浏览器,添加两个商品,可以看到徽章和总计都发生了变化
删除购物车商品
删除商品要修改cart
模块中的state
,所以要在cart
模块中添加一个mutation
- 在
card
的mutation
中添加
const mutations = {addToCart (state, product) {...},// 删除购物车商品,第二个参数是商品iddeleteFromCart (state, prodId) {// 使用数组的findIndex获取索引const index = state.cartProducts.findIndex(item => item.id === prodId)// 判断这个是不是等于-1,如果不是说明有这个商品,就执行后面的删除该元素// splice接收删除元素的索引,第二个元素是删除几个元素,这里写1index !== -1 && state.cartProducts.splice(index, 1)}
}
- 在
components/pop-cart.vue
中引用
<template><el-popoverwidth="350"trigger="hover"><el-table :data="cartProducts" size="mini">...<el-table-column label="操作"><!-- 获取当前元素的id,添加slot插槽 --><template v-slot="scope"><el-button size="mini" @click="deleteFromCart(scope.row.id)">删除</el-button></template></el-table-column></el-table>...</el-popover>
</template><script>
// 导入mapMutations模块
import { mapGetters, mapMutations, mapState } from 'vuex'
export default {name: 'PopCart',computed: {...},methods: {// 把cart模块中的deleteFromCart映射到methods中...mapMutations('cart', ['deleteFromCart'])}
}
</script><style></style>
- 在浏览器中预览,添加商品之后点击删除按钮当前商品删除成功
购物车列表组件
- 购物车列表
- 全选操作
- 数字加减并统计小计
- 删除功能
- 统计选中商品价格数量
购物车列表
- 在views/cart.vue中引入vuex
<template><div>...<!-- 这里也要写成cartProducts --><el-table:data="cartProducts"style="width: 100%">...</el-table>...</div>
</template><script>
// 导入vuex
import { mapState } from 'vuex'
export default {name: 'Cart',computed: {// 将cartProducts映射到computed中...mapState('cart', ['cartProducts'])}
}
</script><style></style>
- 在浏览器中看,添加商品到我的购物车,购物车列表中有了对应的数据
全选操作
- 点击子
checkbox
,选中变不选中,不选中变选中- 子
checkbox
的状态是其商品的isChecked
的值决定 - 使用
mutation
- 子
- 点击父
checkbox
的时候,子checkbox
与父保持一致,并且会重新进行计算值。全部点中子checkbox
,父checkbox
也会选中- 父
checkbox
的状态,是购物车页面单独显示的,不需要写到store
中, 直接写到当前组件。 - 其依赖子
checkbox
的isChecked
状态,所以使用计算属性 - 改变父
checkbox
的状态,store
的子状态也需要改变,不需要定义方法,设置其set
方法即可
- 父
- 先写改变子
checkbox
状态的mutation
const mutations = {addToCart (state, product) {...},deleteFromCart (state, prodId) {...},// 改变所有商品的isChecked属性// 需要两个参数,第二个是checkbox的状态updateAllProductChecked (state, checked) {// 给每个商品的isChecked属性为checkbox状态state.cartProducts.forEach(prod => {prod.isChecked = checked})},// 改变某个商品的isChecked属性// 需要两个属性,第二个是商品对象,这里是解构,一个是checked,一个是idupdateProductChecked (state, {checked,prodId}) {// 找到对应id的商品对象const prod = state.cartProducts.find(item => item.id === prodId)// 如果商品对象存在就给其isChecked进行赋值prod && (prod.isChecked = checked)}
}
- 在
views/cart.vue
中进行引入修改
- 引入
mutation
- 找到父
checkbox
绑定计算属性 - 定义
checkbox
计算属性,完成get
和set
- 子
checkbox
中使用
<template><div>...<el-table:data="cartProducts"style="width: 100%"><el-table-columnwidth="55"><template v-slot:header><!-- 2. 这里绑定一个v-model,计算属性 --><el-checkbox size="mini" v-model="checkedAll"></el-checkbox></template><!-- 4. 这里不能直接绑定v-model,因为我们绑定的是vuex的状态,不能直接更改状态4.1 先绑定其isChecked属性4.2 注册改变事件change,当checkbox改变的时候调用change,接收两个参数,id就通过scope.row获取,checked状态就通过$event获取 --><template v-slot="scope"><el-checkboxsize="mini":value="scope.row.isChecked"@change="updateProductChecked({prodId: scope.row.id,checked: $event})"></el-checkbox></template></el-table-column>...</el-table>...</div>
</template><script>
import { mapMutations, mapState } from 'vuex'
export default {name: 'Cart',computed: {...mapState('cart', ['cartProducts']),// 3. 父checkbox的状态,因为有get和set所以直接写成对象形式checkedAll: {// 返回当前购物车的商品是否都是选中状态,如果有一个没有选中直接返回falseget () {return this.cartProducts.every(prod => prod.isChecked)},// 状态改变的时候触发的方法,需要一个参数,checkbox的状态set (value) {this.updateAllProductChecked(value)}}},methods: {// 1. 将cart模块的mutations映射到methods...mapMutations('cart', ['updateAllProductChecked', 'updateProductChecked'])}
}
</script><style></style>
- 打开浏览器,选中商品进入购物车,可以对全选框进行点击
数字加减并统计小计
- 在
cart
模块中,定义一个mutation
方法,更新商品
const mutations = {...// 更新商品,把商品id和count进行解构updateProduct (state, { prodId, count }) {// 找到当前商品const prod = state.cartProducts.find(prod => prod.id === prodId)// 如果找到了就更新数量和总价if (prod) {prod.count = countprod.totalPrice = count * prod.price}}
}
- 去
cart.vue
中添加一个mapMutations
<script>
...
export default {...methods: {// 将cart模块的mutations映射到methods...mapMutations('cart', ['updateAllProductChecked','updateProductChecked','updateProduct'])}
}
</script>
- 在数字框中进行方法绑定
<el-table-columnprop="count"label="数量"><!-- 这里先定义一个插槽,绑定value是count,定义一个改变的change方法,将updateProduct传入两个参数,一个是id,一个是当前input的值$event --><template v-slot="scope"><el-input-number :value="scope.row.count" @change="updateProduct({prodId: scope.row.id,count: $event})" size="mini"></el-input-number></template></el-table-column>
- 在浏览器中查看,添加商品之后,修改数字,会有对应的商品数量和小计
删除功能
- 之前已经在
cart.js
的模块中有了删除商品的mutation
,这里直接使用,在cart.vue
中添加
<script>
...
export default {...methods: {// 将cart模块的mutations映射到methods...mapMutations('cart', ['updateAllProductChecked','updateProductChecked','updateProduct','deleteFromCart'])}
}
</script>
- 在上面的删除按钮中定义方法
<el-table-columnlabel="操作"><!-- 定义一个插槽,删除按钮绑定事件,传入商品id --><template v-slot="scope"><el-button size="mini"@click="deleteFromCart(scope.row.id)">删除</el-button></template>
</el-table-column>
- 浏览器中,添加商品之后进入购物车页面,点击删除按钮可以删除整个商品。
统计总数量和总钱数
统计的过程中需要添加条件,判断当前商品是否是选中状态。
- 在
cart.js
的getters
中添加商品数量和总价的方法,并且对选中状态进行判断
const getters = {totalCount (state) {...},totalPrice () {...},// 选中的商品数量checkedCount (state) {// 返回前判断是否是选中状态,如果是就进行添加,并且返回sumreturn state.cartProducts.reduce((sum, prod) => {if (prod.isChecked) {sum += prod.count}return sum}, 0)},// 选中的商品价格,同理上面checkedPrice () {return state.cartProducts.reduce((sum, prod) => {if (prod.isChecked) {sum += prod.totalPrice}return sum}, 0)}
}
- 在
cart.vue
中导入mapGetters
<script>
import { mapGetters, mapMutations, mapState } from 'vuex'
export default {name: 'Cart',computed: {...mapState('cart', ['cartProducts']),// 将cart模块中的getters映射到computed中...mapGetters('cart', ['checkedCount', 'checkedPrice']),...},...
}
</script>
- 在总价格处引用
<div><p>已选 <span>{{ checkedCount }}</span> 件商品,总价:<span>{{ checkedPrice }}</span></p><el-button type="danger">结算</el-button>
</div>
处理金额小数的问题
多添加商品的时候发现商品金额会出现很多位小数的问题,所以这里进行处理
-
mutations
中会价格的乘积进行保留两位小数的操作
const mutations = {// 添加商品addToCart (state, product) {const prod = state.cartProducts.find(item => item.id === product.id)if (prod) {prod.count++prod.isChecked = true// 小计 = 数量 * 单价prod.totalPrice = (prod.count * prod.price).toFixed(2)console.log(prod.totalPrice)} else {...}},// 更新商品updateProduct (state, { prodId, count }) {const prod = state.cartProducts.find(prod => prod.id === prodId)if (prod) {prod.count = count// 保留两位小数prod.totalPrice = (count * prod.price).toFixed(2)}}
}
- 在
getters
中将总价进行保留两位小数,记得转化成数字
const getters = {// 价格总计totalPrice () {return state.cartProducts.reduce((sum, prod) => sum + Number(prod.totalPrice), 0).toFixed(2)},// 选中的商品价格checkedPrice () {return state.cartProducts.reduce((sum, prod) => {if (prod.isChecked) {sum += Number(prod.totalPrice)}return sum}, 0).toFixed(2)}
}
本地存储
刷新页面,购物车的数据就会消失,因为我们把数据添加到了内存中存储,而实际购物的时候,有两种存储方式:
- 如果用户登录,购物车的数据是在服务器中
- 如果用户没有登录,购物车的数据是存在本地存储中
现在实现本地存储的功能
- 首先在
cart.js
中,首次进入界面的时候,从本地获取数据
const state = {// 从本地获取购物车商品数据,如果没有初始化为空数组cartProducts: JSON.parse(window.localStorage.getItem('cart-products')) || []
}
- 在
mutations
中更改数据,所以每次更改过的数据,都需要记录到本地存储中,这里使用vuex
的插件,在index.js
中
...
Vue.use(Vuex)const myPlugin = store => {store.subscribe((mutation, state) => {// mutation 的格式为 { type, payload }// type里面的格式是cart/cartProducts// state 的格式为 { cart, products }if (mutation.type.startsWith('cart/')) {// 本地存储cartProductswindow.localStorage.setItem('cart-products', JSON.stringify(state.cart.cartProducts))}})
}
export default new Vuex.Store({...// 将myPlugin挂载到Store上plugins: [myPlugin]
})
- 刷新浏览器可以看到购物车的商品列表的数据还存在。
完整案例
vuex-cart-temp

喜欢的朋友记得点赞、收藏、关注哦!!!
相关文章:
Vuex(二) —— 用Vuex完成购物车案例
目录 需求需求分析 组件分析组件通信 开发 准备环境准备模块结构商品列表组件 展示商品列表添加购物车 我的购物车组件 购物车列表商品数量和统计功能删除购物车商品 购物车列表组件 购物车列表全选操作数字加减并统计小计删除功能统计总数量和总钱数处理金额小数的问题 本地存…...
数字孪生的浪潮:从虚拟镜像到现实世界的 IT 变革
文章目录 数字孪生的本质:物理与虚拟的实时镜像数字孪生的演进:从工业试验到全行业热潮核心技术:数字孪生的基石与工具链物联网(IoT):数据采集云计算与大数据:模型存储AI 与机器学习:…...
Web开发之三层架构
实例: 分层解耦 耦合:衡量软件中各个层/各个模块的依赖关联程度。 内聚:软件中各个功能模块内部的功能联系。 软件设计原则:高内聚低耦合 控制反转:Inversion 0f Control,简称IQC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为…...
社交电商和泛娱乐平台出海南美市场支付方式与策略
随着中国社交电商和泛娱乐平台加速全球化布局,南美市场凭借庞大的人口基数、快速增长的互联网渗透率和活跃的社交媒体使用率,成为出海企业的重要战略要地。然而,这片"新蓝海"的支付生态复杂多元,信用卡欺诈率高企,现金支付仍占主导,不同国家支付偏好差异显著。…...
Miniconda Windows10版本下载和安装
Miniconda Windows10版本下载和安装 步骤1:Miniconda3下载和安装 # 1、下载地址(Windows 64位) https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe #2、双击进行安装 # 安装注意事项: 1. 安装路径建议&a…...
编译原理:由浅入深从语法树到文法类型
文法与语言基础:从语法树到文法类型 文法(Grammar)和语言(Language)是计算机科学和语言学中解析和理解语言结构的核心概念。无论是编程语言的编译器设计,还是自然语言处理(NLP)中的…...
初识Python
哈哈哈,为了让初学者对python进一步了解,懒惰的博主特地去问了AI,如何更加形象的形容python这一么语言 🌟 Python 是什么? 想象一下,编程语言是一群性格各异的人: C语言:穿格子衫的…...
C++ —— 正向迭代器与反向迭代器
目录 1. 正向迭代器(Forward Iterator) 1.1 基本概念 1.2 核心特性 1.3 典型使用 1.4 重要特点 2. 反向迭代器(Reverse Iterator) 2.1 基本概念 2.2 核心特性 2.3 典型使用 2.4 重要特点 3. 正反迭代器对比 4. 正反迭代…...
FDA会议类型总结
1. 会议类型及目的 1.1 Type A会议 1.1.1 争议解决会议 用于解决药物研发过程中与FDA产生的争议,明确双方分歧点。 通过讨论达成共识,避免因争议影响研发进度。 1.1.2 临床保留讨论会议 针对临床试验中出现的问题进行讨论,决定是否保留临床试验。 综合评估临床试验的安全性…...
数据结构算法竞赛训练网站OJ(Online Judge)
都是个人使用过的算法训练OJ,存个档 洛谷 https://www.luogu.org/ 个人使用最多的,题目较全,每题都有题解博客,社区比较完善。 PTA https://pintia.cn/ 学习数据结构和练习天梯赛的时候使用的。 牛客 https://ac.nowcoder.co…...
快速搭建对象存储服务 - Minio,并解决临时地址暴露ip、短链接请求改变浏览器地址等问题
本文要解决的问题 基础的Minio下载安装、java操作方法、完整的工具类。 使用minio时需要注意的地方: 使用Minio的时候,生成资源的临时访问链接时,生成的地址IP是真实的IP和端口,不安全,怎么办? 生成的Min…...
2025年- H11-Lc118-53.最大子数组和(普通数组)---java版
1.题目描述 2.思路 用动态规划方法来解决【最大子数组和】(Maximum Subarray)问题。 pre(当前位置最大和)、 maxAns(全局最大和) 3.代码实现 class H53 {public int maxSubArray(int[] nums) {int curr…...
基于蓝牙Beacon人员导航方案
基于蓝牙Beacon人员导航方案 一、室内定位市场痛点与技术选择 大型商场(单层超2万㎡)和医院(科室超200个)的复杂空间中,传统GPS信号衰减超90%,用户平均寻路耗时10-15分钟,30%购物决策因“找店…...
mysql模糊多次OR查询某一个字段,针对这个字段进行查询分组
一. 需求 有一个mysql表t_test,有两个字段className和studentStr 其中studentStr会用来模糊查询 假如现在有6条数据 1.studentStr字段数据:“小明,小红,小同,小芳,小特,小兰” 2.studentStr字段数据:“小明,小红,小同” 3.studentStr字段数据:“小芳,小特,小兰” 4.stud…...
OpenGL进阶系列21 - OpenGL SuperBible - blendmatrix 例子学习
一:概述 颜色输出阶段是 OpenGL 渲染管线中最后一个阶段。它决定了片段在离开片段着色器之后,最终显示在用户屏幕上的颜色值。颜色输出阶段最重要的一个操作就是混合。本例子重点介绍下OpenGL中的混合操作。 对于每个通过片段测试(per-fragment tests)的片段,会执行混合操…...
阿里语音处理工具ClearerVoice-Studio项目上手指南
ClearerVoice-Studio:开源语音处理全能工具箱 🚀 核心功能速览 语音增强:消除环境噪声(支持16kHz/48kHz)语音分离:多人对话场景的说话人分离(8kHz/16kHz)超分辨率:16kHz→48kHz音质提升目标说话人提取:基于人脸/手势/EEG的多模态提取语音质量评估:9种客观评价指标A…...
31、简要描述Promise.all的用途
Promise.all 是 JavaScript 中用于处理多个异步操作的核心方法,其核心用途是并行聚合多个 Promise 的结果,并在所有操作成功时统一返回结果数组。以下是其关键特性与典型应用场景的简要描述: 核心功能 1、并行执行 接收一个 Promise 数组&…...
OpenVLA-OFT
TL;DR 2025 年斯坦福提出的 OpenVLA 工作的续作 OpenVLA-OFT,优化 VLA 能够有效适应新的机器人平台和任务,优化的技术主要有并行解码、动作块处理、连续动作、L1 回归和(可选的)FiLM 语言调节 Paper name Fine-Tuning Vision-La…...
2025“钉耙编程”中国大学生算法设计春季联赛(8)10031007
题目的意思很好理解找从最左边到最右边最短路(BFS) #include <bits/stdc.h> using namespace std; int a[510][510]; // 存储网格中每个位置是否有障碍(1表示有障碍,0表示无障碍) int v[510][510]; // 记录每…...
代码随想录算法训练营第六十一天 | floyd算法
Floyd 算法精讲 题目链接:97. 小明逛公园 文章讲解:代码随想录 思想:本题是多源最短路,即求多个起点到多个终点的多条最短路径。用Floyd 算法。 Floyd 算法对边的权值正负没有要求,都可以处理,Floyd算法…...
[三分钟]web自动化测试(三):selenium自动化测试常用函数(下)
文章目录 4.等待4.1 强制等待4.2 隐式等待4.3 显式等待 5.浏览器导航5.1 浏览器的前进、后退、刷新5.2 打开网站 6. 弹窗6.1 确认和取消6.2 输入信息 7. 文件上传 4.等待 如果页面渲染的速度赶不上代码执行的速度,可能会因为渲染过慢出现自动化误报的问题。 此时可…...
文档声明:HTML文档的基石
在前端开发的世界里,文档声明虽是一个看似不起眼的细节,却在网页的解析和渲染过程中扮演着至关重要的角色。今天,就让我们深入探讨文档声明的奥秘,揭开它背后的原理和重要性。 一、文档声明的定义与作用 文档声明,顾…...
光学涡旋干涉仪
一、什么是涡旋干涉仪? 涡旋光束一般指电场含有螺旋相位因子exp(iℓθ)的光束,其中ℓ为拓扑荷数,θ为方位角,其波前为螺旋形,光束中心存在相位奇点,因此涡旋光束的光强轮廓是中心强度为零的圆环。早在1992…...
Wireshark快速入门--对启动的后端程序进行抓包
怎么对自己启动的后端程序进行抓包? 1. 安装并启动 Wireshark 你要先从 Wireshark 官网 下载对应系统的安装包,然后进行安装。安装完成后,启动该软件。 可以快速入门可以参考博文:从零开始学 Wireshark:网络分析入门…...
ViTa-Zero:零样本视觉触觉目标 6D 姿态估计
25年4月来自Amazon 公司、Brown 大学和 Northestern 大学的论文“ViTa-Zero: Zero-shot Visuotactile Object 6D Pose Estimation”。 目标 6D 姿态估计是机器人技术中的一项关键挑战,尤其对于操作任务而言。虽然先前结合视觉和触觉(视觉触觉࿰…...
继承(c++版 非常详细版)
一. 继承的概念及定义 1.1 继承的概念 继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有 类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类。继…...
解锁服务器迁移的未来:《2025 服务器迁移效率白皮书》(附下载)
一、背景🏙️ 随着全球数字化转型的不断加速,企业在推动 IT 基础设施现代化过程中,面临着前所未有的服务器迁移挑战。传统的迁移工具和多云、混合云环境带来的复杂性,导致迁移效率低、成本高、人力投入大,从而严重阻碍…...
STM32的Flash映射双重机制
在STM32微控制器中,存在一个重要的内存映射特性:Flash存储器可以同时出现在两个不同的地址区域,而且可以通过重映射功能改变CPU启动时从哪个地址获取初始指令。 STM32的Flash映射双重机制 当描述"通常起始于地址0x00000000,…...
简单了解跨域问题
什么是跨域? 跨域是浏览器基于同源策略的安全机制。 如何两个请求之间,域名,端口,协议三者中有任意一个不同,就会产生跨域问题。 跨域的解决方案 1. CORS(跨源资源共享) 后端通过设置响应头声…...
sql学习笔记(四)
今天看到一个sql题,“近30天,******”,这里需要用到一个函数,date_add,其作用是在指定日期基础上添加一个时间间隔。 语法(以mysql为例): DATE_ADD(date, INTERVAL value unit) d…...
基于 Java 的实现前端组装查询语句,后端直接执行查询方案,涵盖前端和后端的设计思路
1. 前端设计 前端负责根据用户输入或交互条件,动态生成查询参数,并通过 HTTP 请求发送到后端。 前端逻辑: 提供用户界面(如表单、筛选器等),让用户选择查询条件。将用户选择的条件组装成 JSON 格式的查询参数。发送 HTTP 请求(如 POST 或 GET)到后端。示例: 假设用…...
反射与注解实现动态功能扩展案例-插件系统
学海无涯,志当存远。燃心砺志,奋进不辍。 愿诸君得此鸡汤,如沐春风,事业有成。 若觉此言甚善,烦请赐赞一枚,共励学途,同铸辉煌! 开发一个需要高度扩展性的应用,比如Web框…...
auto(x) decay copy
该提案为auto又增加了两个新语法:auto(x) 和auto{x}。两个作用一样,只是写法不同,都 是为x 创建一份拷贝。 为什么需要这么个东西?看一个例子: void bar(const auto&);void foo(const auto& param) {auto co…...
基于STM32、HAL库的DS2411R安全验证及加密芯片驱动程序设计
一、简介: DS2411R是Maxim Integrated(现为Analog Devices)生产的一款1-Wire硅序列号芯片,具有以下特点: 64位唯一ROM序列号(包括8位家族码、48位序列号和8位CRC校验码) 工作电压范围:2.8V至5.25V 工作温度范围:-40C至+85C 采用TO-92或SOT-223封装 通过1-Wire协议通信…...
疫苗接种体系进入“全生命周期”时代:公共卫生治理再提速
疫苗接种体系进入“全生命周期”时代:公共卫生治理再提速 在防控重大传染病的国家公共卫生战略中,疫苗接种始终处于基础性、先导性地位。2025年4月25日是第39个全国儿童预防接种日,活动主题为“打疫苗、防疾病、保健康”。近年来,…...
zynq 7010 PS 串口打印
前言 之前写过一篇文章《zynq 7010 PL 点灯例程》,介绍的是 zynq PL 部分的使用,今天这篇文章则是介绍 zynq PS 部分的使用。 在此之前,先总结点题外话 PL 编程,核心思想是生成 bitstream 文件,加载到 FPGA 运行PS …...
【补题】ACPC Kickoff 2025 F. Kinan The Bank Robber
题意:给出长度为n的序列,接下来给出了两个包裹,你可以选择把数字放进这两个包裹当中,要求你放的的方式,最终会让包裹内的数字双双互质,请你给出你的放法,如果没有输出-1 思路: 1.包…...
局域网传文件——基于flask实现
项目地址 git clone gitgitee.com:xhdx/co_-shared_-doc_in_-local_-net.git 所需python包 flask2.2.3 markdown3.4.1 bleach5.0.1 通过局域网的方式实现文件夹共享,共享的文件会放在uploads这个文件夹下: 运行界面: 包括预览、删除、下载等…...
苍穹外卖10
WebSocket WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信----浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 HTTP协议和WebSocket协议对比: HTTP是短链接 WebSocke…...
第一天 车联网定义、发展历程与生态体系
前言 车联网(Internet of Vehicles, IoV)作为物联网(IoT)在汽车领域的延伸,正在彻底改变人们的出行方式。无论是自动驾驶、远程诊断,还是实时交通优化,车联网技术都扮演着核心角色。本文将从零…...
大模型(LLMs)强化学习—— PPO
一、大语言模型RLHF中的PPO主要分哪些步骤? 二、举例描述一下 大语言模型的RLHF? 三、大语言模型RLHF 采样篇 什么是 PPO 中 采样过程?介绍一下 PPO 中 采样策略?PPO 中 采样策略中,如何评估“收益”? …...
麻衣相法【麻衣相士】开篇
好久没有发布新的文章了,主要最近一方面没看书,时间基本都用来打游戏了;另一方面看的几本书实在是看不懂,就更不能写上来了。不过今天看到了《麻衣相法》这本书,就又点燃了本人的兴趣,以后失业了,可以摆个小摊子谋生! 话不多说,先把这本书开始的针对人的面部部位进行各…...
vLLM技术解析:大语言模型推理服务的性能革新引擎
vLLM大模型 vLLM(Vectorized Large Language Model Serving System)是由加州大学伯克利分校计算机系统研究团队开发的下一代大语言模型推理服务系统。作为专为现代化AI部署设计的开源框架,该系统通过突破性的内存架构创新和计算流程优化&…...
《无刷空心杯电机减速机选型及行业发展趋势》
无刷空心杯电机作为高精度驱动系统的核心部件,通常需搭配减速机以实现低转速、高扭矩输出。以下是当前主流的减速机类型、市场占比、参数对比及优劣势分析,结合行业数据与典型应用场景展开说明: 一、主流减速机类型及市场占比 1. 行星减速机 市场占比:约 45%-55%(工业自…...
Java锁的升级流程详解:无锁、偏向锁、轻量级锁、重量级锁
在Java中,为了在多线程并发场景下既保证线程安全,又尽可能提高性能,JVM针对synchronized实现了锁的优化升级机制。 锁可以从无锁逐步升级到偏向锁、轻量级锁,最后是重量级锁。 话不多说,发车! 一、无锁&am…...
terraform local-exec与remote-exec详解
在 Terraform 中,local-exec 和 remote-exec 是两种常用的 provisioner(资源调配器),用于在资源创建前后执行脚本或命令。它们的核心区别在于执行位置:local-exec 在运行 Terraform 的本地机器上执行命令,而…...
武装Burp Suite工具:APIKit插件_接口安全扫描.
武装Burp Suite工具:APIKit插件_接口安全扫描. API安全是指通过技术手段和管理措施保护应用程序接口(API)免受未授权访问、数据泄露或恶意攻击的防护体系,核心措施包括身份认证(如OAuth2.0/JWT)、权限控制…...
数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记6
前言 经过前面几篇文章的介绍,已经完成了对于数据查询操作的介绍,接下来,本篇文章将介绍数据更新这一板块,包括插入数据、修改数据以及删除数据三种操作方法。 注:本文中所涉及的数据库前文中已经介绍(指…...
如何在idea中写spark程序
1. 安装配置 Java 和 Scala Java:确保已安装合适版本的 Java Development Kit(JDK),并配置好 JAVA_HOME 环境变量。Scala:由于 Spark 常用 Scala 语言编写,需安装 Scala 开发环境。可在 IDEA 中通过 Se…...
Linux428 chmod 0xxx 1xxx 2xxx 4xxx;umask;chown 属主属组 软件包rpm
sudo: 账户过期,或 PAM 配置缺少 sudo 使用的“account”节,联系您的系统管理员 这样子有没有用嘞 不行 为什么使用caozx26用户sudo修改了shop文件夹强制位,shop文件夹权限中不显示 成功了?真奇怪 查看文件夹权限用 -ld ch…...