1、制作头部
<!-- #ifdef MP --> <search-slot> <view class="left" slot="left"> </view> <view class="center" slot="center"> 购物车 </view> <view class="right" slot="right" A> <view v-if="isEdit">编辑</view> <view v-else>完成</view> </view> </search-slot> <!-- #endif -->
样式
.left { width: 100rpx; align-items: center; text-align: center; } .center { flex: 1; text-align: center; } .right { width: 100rpx; text-align: center; align-items: center; }
2、点击按钮完成和编辑进行切换
给按钮传一个点击事件进行判断即可
data() { return { isEdit:true, } }, tab(){ this.isEdit = !this.isEdit }
3、编辑底部合计部分随着编辑一同显示
<template v-if="isEdit"> <view class="d-flex a-center position-fixed left-0 right-0 bottom-0 ju border-top border-light-secondary a-stretch" style="height: 100rpx;z-index: 100;"> <label class="radio d-flex a-center j-center flex-shrink" style="width: 120rpx;"> <radio color="#FD6801" ></radio> </label> <view class="flex-1 d-flex a-center j-center font-md"> 合计 <p-price>{{totalPrice}}</p-price> </view> <view class="flex-1 d-flex a-center j-center main-bg-color text-white font-md" hover-class="main-bg-hover-color"> 结算 </view> </view> </template>
微信小程序中的hover-class属性
微信小程序中,可以用 hover-class 属性来指定元素的点击态效果。但是在在使用中要注意,大部分组件是不支持该属性的。
目前支持 hover-class 属性的组件有三个:view、button、navigator。
4、在完成页面中显示底部样式
<template v-else> <view class="d-flex a-center position-fixed left-0 right-0 bottom-0 ju border-top border-light-secondary a-stretch" style="height: 100rpx;z-index: 100;"> <label class="radio d-flex a-center j-center flex-shrink" style="width: 120rpx;" > <radio color="#FD6801" ></radio> </label> <view class="flex-1 d-flex a-center j-center font-md main-bg-color text-white"> 移入收藏 </view> <view class="flex-1 d-flex a-center j-center bg-danger text-white font-md" hover-class="main-bg-hover-color" > 删除 </view> </view> </template>
条件编译
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。
写法:以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾。
#ifdef:if defined 仅在某平台存在
#ifndef:if not defined 除了某平台均存在
%PLATFORM%:平台名称
条件编译写法 说明
#ifdef APP-PLUS
需条件编译的代码
#endif
仅出现在 App 平台下的代码
#ifndef H5
需条件编译的代码
#endif
除了 H5 平台,其它平台均存在的代码
#ifdef H5 || MP-WEIXIN
需条件编译的代码
#endif
在 H5 平台或微信小程序平台存在的代码(这里只有||,不可能出现&&,因为没有交集)
%PLATFORM% 可取值如下:
值 生效条件
VUE3 HBuilderX 3.2.0+ 详情
APP-PLUS App
APP-PLUS-NVUE或APP-NVUE App nvue
H5 H5
MP-WEIXIN 微信小程序
MP-ALIPAY 支付宝小程序
MP-BAIDU 百度小程序
MP-TOUTIAO 字节跳动小程序
MP-LARK 飞书小程序
MP-QQ QQ小程序
MP-KUAISHOU 快手小程序
MP-360 360小程序
MP 微信小程序/支付宝小程序/百度小程序/字节跳动小程序/飞书小程序/QQ小程序/360小程序
QUICKAPP-WEBVIEW 快应用通用(包含联盟、华为)
QUICKAPP-WEBVIEW-UNION 快应用联盟
QUICKAPP-WEBVIEW-HUAWEI 快应用华为
基本样式完成后接下来用vuex来写数据
uniapp中自带vuex所以无需再安装,直接调用即可
创建一个store文件夹里面存放index.js,代码如下:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) import cart from './modules/cart.js' let store = new Vuex.Store({ modules:{ cart } }) export default store
在main.js中引入
在store文件夹中再新建一个modules文件里面包裹一个cart.js
state中填入list列表
list: [ { checked: false, id: 11, title: "商品标题111", cover: "/static/images/demo/list/1.jpg", // 选中商品属性 attrs: [{ title: "颜色", selected: 0, list: [{ name: '火焰红', }, { name: '炭黑', }, { name: '冰川兰', } ] }, { title: "容量", selected: 0, list: [{ name: '64GB', }, { name: '128GB', }, ] }, { title: "套餐", selected: 0, list: [{ name: '标配', }, { name: '套餐一', }, { name: '套餐二', } ] }, ], pprice: 336, num: 1, minnum: 1, maxnum: 10, // 该商品最大商品数,跟库存有关 }, { checked: false, id: 12, title: "商品222", cover: "/static/images/demo/list/1.jpg", // 选中商品属性 attrs: [{ title: "颜色", selected: 0, list: [{ name: '火焰红', }, { name: '炭黑', }, { name: '冰川兰', } ] }, { title: "容量", selected: 0, list: [{ name: '64GB', }, { name: '128GB', }, ] }, { title: "套餐", selected: 0, list: [{ name: '标配', }, { name: '套餐一', }, { name: '套餐二', } ] }, ], pprice: 200, num: 1, minnum: 1, maxnum: 10, // 该商品最大商品数,跟库存有关 }, { checked: false, id: 13, title: "商品标题333", cover: "/static/images/demo/list/1.jpg", // 选中商品属性 attrs: [{ title: "颜色", selected: 0, list: [{ name: '火焰红', }, { name: '炭黑', }, { name: '冰川兰', } ] }, { title: "容量", selected: 0, list: [{ name: '64GB', }, { name: '128GB', }, ] }, { title: "套餐", selected: 0, list: [{ name: '标配', }, { name: '套餐一', }, { name: '套餐二', } ] }, ], pprice: 100, num: 2, minnum: 1, maxnum: 10, // 该商品最大商品数,跟库存有关 } ], selectedAll:[]//储存选中数据
也可以单独这么写:
// 页面路径:store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); //vue的插件机制 //Vuex.Store 构造器选项 const store = new Vuex.Store({ state: { list: [{ checked: false, //按钮状态 id: 11, // id用来区分每个不同的按钮 title: "商品标题111", cover: "/static/images/demo/list/1.jpg", // 选中商品属性 attrs: [{ title: "颜色", selected: 0, // 选中的第几个,默认从0开始 list: [{ name: '火焰红', }, { name: '炭黑', }, { name: '冰川兰', } ] }, { title: "容量", selected: 0, list: [{ name: '64GB', }, { name: '128GB', }, ] }, { title: "套餐", selected: 0, //选中状态 list: [{ name: '标配', }, { name: '套餐一', }, { name: '套餐二', } ] }, ], pprice: 336, //商品价格 num: 1, // 初始值 minnum: 1, // 按钮最大值 maxnum: 10, // 该商品最大商品数,跟库存有关 }, { checked: false, id: 12, title: "商品222", cover: "/static/images/demo/list/1.jpg", // 选中商品属性 attrs: [{ title: "颜色", selected: 0, list: [{ name: '火焰红', }, { name: '炭黑', }, { name: '冰川兰', } ] }, { title: "容量", selected: 0, list: [{ name: '64GB', }, { name: '128GB', }, ] }, { title: "套餐", selected: 0, list: [{ name: '标配', }, { name: '套餐一', }, { name: '套餐二', } ] }, ], pprice: 200, num: 1, minnum: 1, maxnum: 10, // 该商品最大商品数,跟库存有关 }, { checked: false, id: 13, title: "商品标题333", cover: "/static/images/demo/list/1.jpg", // 选中商品属性 attrs: [{ title: "颜色", selected: 0, list: [{ name: '火焰红', }, { name: '炭黑', }, { name: '冰川兰', } ] }, { title: "容量", selected: 0, list: [{ name: '64GB', }, { name: '128GB', }, ] }, { title: "套餐", selected: 0, list: [{ name: '标配', }, { name: '套餐一', }, { name: '套餐二', } ] }, ], pprice: 100, num: 2, minnum: 1, maxnum: 5, // 该商品最大商品数,跟库存有关 } ], selectedAll: [] //储存选中数据 }, getters: { // 购物车为空时出现购物车图标 disSelect(state) { return state.list.length === 0; }, //全部选中 checkedAll(state) { return state.list.length === state.selectedAll.length }, //计算总价 totalPrice(state) { let total = 0 state.list.forEach(v => { /* if(state.selectedAll.indexOf(v.id)!=-1){ total += v.pprice * v.num } */ console.log(v.num); if (v.checked) { total += v.pprice * v.num } }) return total }, //合计按钮不可用状态 disabled(state) { if (state.list.length === 0) { state.list.checked = false return true } } }, mutations: { //单选按钮 selectItem(state, index) { var id = state.list[index].id var i = state.selectedAll.indexOf(id) if (i > -1) { // 取消当前商品选中状态 state.list[index].checked = false // 移除选中列表中的当前商品 return state.selectedAll.splice(i, 1) } // 选中 state.list[index].checked = true state.selectedAll.push(id) console.log(state.selectedAll); }, //全选 selectAll(state) { state.selectedAll = [] state.list.map(v => { v.checked = true state.selectedAll.push(v.id) }) /* state.selectedAll = state.list.map(v=>{ v.checked = true return v.id }) */ }, //全不选 noselectAll(state) { state.list.map(v => { v.checked = false }) state.selectedAll = [] }, //删除商品 delgoods(state) { uni.showModal({ content: '您确定要删除吗', success: () => { // commit('delgoods') state.list = state.list.filter(v => { console.log(state.selectedAll.indexOf(v.id) === -1); return state.selectedAll.indexOf(v.id) === -1 }) state.selectedAll = [] //清空id }, fail: (err) => { console.log(err); } }) } }, actions: { doselectAll({ getters, commit }) { // 传getters中的状态,如果全选按钮是开启的那么就返回全不选,否则就在跳回全选 getters.checkedAll ? commit('noselectAll') : commit('selectAll') }, } }) export default store
数据基本完成,完成后再写个购物车为空的页面,如果没有获取到数据,那么购物车就显示空
<template v-if="disSelect"> <view class="py-5 d-flex a-center j-center bg-white"> <view class="iconfont icon-gouwuche text-light-muted" style="font-size: 50rpx;"></view> <text class="text-light-muted mx-2">购物车还是为空</text> <view class="px-2 py-1 border border-light-secondary rounded" hover-class="bg-light-secondary"> 去逛逛 </view> </view> </template>
用计算属性引入
getters: { // 购物车为空时出现暂无数据购物车图标 disSelect(state){ return state.list.length === 0 } },
在页面用计算属性让其显示list列表
computed: { ...mapState({ list: (state) => state.list }), // 在这里引入 ...mapGetters(['disSelect']) }
全部选中:
计算总价:
按钮出现不可选中状态
单选按钮
全选
全不选
删除
异步接收方法