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 |
仅出现在 App 平台下的代码 |
#ifndef H5 |
除了 H5 平台,其它平台均存在的代码 |
#ifdef H5 || MP-WEIXIN |
在 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'])
}
全部选中:
计算总价:
按钮出现不可选中状态
单选按钮
全选
全不选
删除
异步接收方法