当前位置: 首页 > news >正文

购物车高效开发指南:API与Vuex实战

api层

import request from '@/utils/request'// 加入购物车
export const addCart = (goodsId, goodsNum, goodsSkuId) => {return request.post('/cart/add', {goodsId,goodsNum,goodsSkuId})
}// 获取购物车列表数据
export const getCartList = () => {return request.get('/cart/list')
}// 更新购物车商品数量
export const changeCount = (goodsId, goodsNum, goodsSkuId) => {return request.post('/cart/update', {goodsId,goodsNum,goodsSkuId})
}// 删除购物车商品
export const delSelect = (cartIds) => {return request.post('/cart/clear', {cartIds})
}

store层

import { getCartList, changeCount, delSelect } from '@/api/cart'
import { Toast } from 'vant'export default {namespaced: true,state() {return {cartList: []}},mutations: {setCartList(state, newList) {state.cartList = newList},toggleCheck(state, goodsId) {const goods = state.cartList.find((item) => item.goods_id === goodsId)goods.isChecked = !goods.isChecked},toggleAllCheck(state, flag) {state.cartList.forEach((item) => {item.isChecked = flag})},changeCount(state, { goodsId, goodsNum }) {const goods = state.cartList.find((item) => item.goods_id === goodsId)goods.goods_num = goodsNum}},actions: {async getCartAction({ commit }) {const { data } = await getCartList()data.list.forEach((item) => {item.isChecked = true})commit('setCartList', data.list)},async changeCountAction({ commit }, { goodsId, goodsNum, goodsSkuId }) {commit('changeCount', { goodsId, goodsNum })await changeCount(goodsId, goodsNum, goodsSkuId)},// 删除购物车数据async delSelect({ commit, getters, dispatch }) {const selCartList = getters.selCartListconst cartIds = selCartList.map((item) => item.id)// console.log(cartIds)await delSelect(cartIds)Toast('删除成功')// 重新获取购物车数据dispatch('getCartAction')}},getters: {// 购物车数量cartTotal(state) {return state.cartList.reduce((sum, item, index) => sum + item.goods_num, 0)},// 已勾选的购物车selCartList(state) {return state.cartList.filter((item) => item.isChecked)},// 已勾选的购物车数量selCount(state, getters) {return getters.selCartList.reduce((sum, item, index) => sum + item.goods_num, 0)},// 已勾选的购物车总价selPrice(state, getters) {return getters.selCartList.reduce((pre, item) => {return pre + item.goods.goods_price_min * item.goods_num}, 0).toFixed(2)},// 是否全选isAllChecked(state) {return state.cartList.every((item) => item.isChecked)}}
}

视图层

<template><div class="cart"><van-nav-bar title="购物车" fixed /><div class="cart-box" v-if="isLogin && cartList.length > 0"><!-- 购物车开头 --><div class="cart-title"><span class="all">共<i>{{ cartTotal || 0 }}</i>件商品</span><span class="edit"><van-icon name="edit" @click="isEdit = !isEdit" />编辑</span></div><!-- 购物车列表 --><div class="cart-list"><div class="cart-item" v-for="item in cartList" :key="item.goods_id"><van-checkbox@click="toggleCheck(item.goods_id)"icon-size="18":value="item.isChecked"></van-checkbox><div class="show" @click="$router.push(`/prodetail/${item.goods_id}`)"><img :src="item.goods.goods_image" alt="" /></div><div class="info"><span class="tit text-ellipsis-2">{{ item.goods.goods_name }}</span><span class="bottom"><div class="price">¥ <span>{{ item.goods.goods_price_min }}</span></div><CountBox@input="(value) => changeCount(value, item.goods_id, item.goods_sku_id)"v-model="item.goods_num"/></span></div></div></div><div class="footer-fixed"><div class="all-check" @click="toggleAllCheck"><van-checkbox icon-size="18" :value="isAllChecked"></van-checkbox>全选</div><div class="all-total"><div class="price"><span>合计:</span><span>¥ <i class="totalPrice">{{ selPrice }}</i></span></div><div v-if="!isEdit" class="goPay" :class="{ disabled: selCount === 0 }" @click="goToPay">结算({{ selCount }})</div><div v-else @click="handleDel" class="delete" :class="{ disabled: selCount === 0 }">删除</div></div></div></div><div class="empty-cart" v-else><img src="@/assets/empty.png" alt="" /><div class="tips">您的购物车是空的, 快去逛逛吧</div><div class="btn" @click="$router.push('/')">去逛逛</div></div></div>
</template><script>
import store from '@/store'
import CountBox from '@/components/CountBox.vue'
import { mapState, mapGetters } from 'vuex'export default {name: 'CartPage',components: {CountBox},computed: {...mapState('cart', ['cartList', 'selPrice']),...mapGetters('cart', ['cartTotal', 'selCount', 'selPrice', 'isAllChecked', 'selCartList']),// 是否登录isLogin() {return store.getters.token}},data() {return {isEdit: false}},created() {// 必须是登录过的用户,才能用户购物车列表if (this.isLogin) {this.$store.dispatch('cart/getCartAction')}},methods: {// 切换选中toggleCheck(goodsId) {this.$store.commit('cart/toggleCheck', goodsId)},// 全选切换toggleAllCheck() {this.$store.commit('cart/toggleAllCheck', !this.isAllChecked)},async changeCount(goodsNum, goodsId, goodsSkuId) {this.$store.dispatch('cart/changeCountAction', {goodsId,goodsSkuId,goodsNum})},// 删除async handleDel() {if (this.selCount === 0) returnawait this.$store.dispatch('cart/delSelect', this.selCount)this.isEdit = false},// 去结算goToPay() {if (this.selCount > 0) {this.$router.push({path: '/pay',query: {mode: 'cart',cartIds: this.selCartList.map((item) => item.id).join(',')}})}}},watch: {isEdit(value) {if (value) {this.$store.commit('cart/toggleAllCheck', false)} else {this.$store.commit('cart/toggleAllCheck', true)}}}
}
</script><style lang="less" scoped>
// 主题 padding
.cart {padding-top: 46px;padding-bottom: 100px;background-color: #f5f5f5;min-height: 100vh;.cart-title {height: 40px;display: flex;justify-content: space-between;align-items: center;padding: 0 10px;font-size: 14px;.all {i {font-style: normal;margin: 0 2px;color: #fa2209;font-size: 16px;}}.edit {.van-icon {font-size: 18px;}}}.cart-item {margin: 0 10px 10px 10px;padding: 10px;display: flex;justify-content: space-between;background-color: #ffffff;border-radius: 5px;.show img {width: 100px;height: 100px;}.info {width: 210px;padding: 10px 5px;font-size: 14px;display: flex;flex-direction: column;justify-content: space-between;.bottom {display: flex;justify-content: space-between;.price {display: flex;align-items: flex-end;color: #fa2209;font-size: 12px;span {font-size: 16px;}}.count-box {display: flex;width: 110px;.add,.minus {width: 30px;height: 30px;outline: none;border: none;}.inp {width: 40px;height: 30px;outline: none;border: none;background-color: #efefef;text-align: center;margin: 0 5px;}}}}}// 购物车为空.empty-cart {display: flex;justify-content: center;flex-direction: column;align-items: center;width: 100%;height: calc(100vh - 100px);img {width: 140px;height: 92px;display: block;margin: 0 auto;}.tips {text-align: center;color: #666;margin: 30px;}.btn {width: 110px;height: 32px;line-height: 32px;text-align: center;background-color: #fa2c20;border-radius: 16px;color: #fff;display: block;margin: 0 auto;}}
}.footer-fixed {position: fixed;left: 0;bottom: 50px;height: 50px;width: 100%;border-bottom: 1px solid #ccc;background-color: #fff;display: flex;justify-content: space-between;align-items: center;padding: 0 10px;.all-check {display: flex;align-items: center;.van-checkbox {margin-right: 5px;}}.all-total {display: flex;line-height: 36px;.price {font-size: 14px;margin-right: 10px;.totalPrice {color: #fa2209;font-size: 18px;font-style: normal;}}.goPay,.delete {min-width: 100px;height: 36px;line-height: 36px;text-align: center;background-color: #fa2f21;color: #fff;border-radius: 18px;&.disabled {background-color: #ff9779;}}}
}
</style>
http://www.dtcms.com/a/560748.html

相关文章:

  • 广州网站建设公司哪家好展厅设计制作
  • 【BFS 解决FloodFill 算法】4. 被围绕的区域(medium)
  • Go channel 的核心概念、操作语义、设计模式和实践要点
  • 现在还可以做夺宝网站怎么让网站被百度搜到
  • 深蓝汽车10月全球销量36792辆 S05销量突破2万辆
  • 四、CSS选择器(续)和三大特性
  • 高职新能源汽车技术专业职业发展指南
  • 初识MySQL:库的操作、数据类型、表的操作
  • AI助力汽车 UI 交互设计
  • 广州市手机网站建设平台有意义网站
  • MySQL到达梦数据库快速替换操作指南
  • Python NumPy广播机制详解:从原理到实战,数组运算的“隐形翅膀”
  • QT背景介绍与环境搭建
  • 【C++:多态】C++多态实现深度剖析:从抽象类约束到虚函数表机制
  • 【软考架构】案例分析-分布式锁
  • 15.5.手机设备信息
  • Mysql基础1
  • 集团网站网页模板网站建设超速云免费
  • HTTPS:现代网站运营的安全基石与价值引擎
  • 老鹰网网站建设外贸是做什么的工作
  • [N_083]基于springboot毕业设计管理系统
  • kotlin学习 lambda编程
  • 如何写好汇报材料经验总结
  • 百度收录的网站标题 --专业做公司网站的机构
  • 视频时间戳PTS和DTS的区别
  • 09-神经网络的结构:描述神经网络的层次化组成和设计
  • 【ComfyUI】Stable Audio 文本生成音频
  • 音视频入门核心概念:容器、编码、流与时间戳
  • 网站的域名每年都要续费建个什么网站赚钱
  • 建站之星破解版在下列软件中