首先大家可以看下演示效果
我先把封裝的幾個組件代碼放到前面。
1.購物車數量加減cart-count.wpy組件
<template>
<view class="cart-count">
<view class="decrease" @tap.stop="decrease">-</view>
<input type="number" value="{{good.num}}" disabled/>
<view class="add" @tap.stop="add">+</view>
</view>
</template>
<script>
import wepy from 'wepy'
export default class CartCount extends wepy.component {
data = {}
props = {
good: {
type: Object,
}
}
components = {}
// 計算屬性
computed = {}
// 方法集
methods = {
add () {
this.good.num++
this.$emit('getGood', this.good)
},
decrease () {
if (this.good.num === 1) return false
this.good.num--
this.$emit('getGood', this.good)
}
}
onLoad () {
console.log(this.good)
}
}
</script>
<style lang='less'>
.cart-count {
display: flex;
width: 100%;
height: 100%;
.decrease {
width: 48rpx;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-left: 1rpx solid #ccc;
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
border-bottom-left-radius: 6rpx;
border-top-left-radius: 6px;
}
.add {
width: 48rpx;
height: 100%;
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
border-right: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
border-top-right-radius: 6rpx;
border-bottom-right-radius: 6rpx;
}
input {
width: 68rpx;
height: 48rpx;
line-height: 48rpx;
min-height: 48rpx;
text-align: center;
font-size: 24rpx;
border: 1px solid #cccccc;
}
}
</style>
2.左拉刪除組件swiper-delete.wpy
<template>
<view class="swiper-item-wrapper">
<view @touchstart="ts" @touchmove="tm" @touchend="te" class="swiper-content" style="{{swiperData.txtStyle}}">
<slot></slot>
</view>
<view class="swiper-actions actions-right">
<view class="swiper-btn del" @tap.stop="del">刪除</view>
</view>
</view>
</template>
<script>
import wepy from 'wepy';
export default class SwiperDelete extends wepy.component {
components = {};
props = {
swiperData: { //父組件傳過來的數據
type: Object,
default: []
}
};
mixins = [];
data = {
delBtnWidth: 180, //單位rpx
startX: 0,
};
computed = {};
methods = {
ts(e) {
// 觸摸開始
let that = this;
if (e.touches.length === 1) {
that.startX = e.touches[0].clientX;
}
},
tm(e) {
// 觸摸過程
let that = this;
if (e.touches.length === 1) {
//手指移動方向水平
let moveX = e.touches[0].clientX; // 這裏的clientX獲取的是屏幕可視區的座標,其實是邏輯像素px,所以要用getEleWidth方法進行換算
//手指起始點位置與移動期間的產值
let disX = that.startX - moveX;
let txtStyle = '';
if (disX === 0 || disX < 0) {
// 往右移動或者沒移動
txtStyle = 'left: 0px';
} else if (disX > 0) {
// 移動距離大於0
txtStyle = 'left:-' + disX + 'px';
if (disX >= that.delBtnWidth) {
// 移動超過刪除按鈕的寬度
txtStyle = 'left:-' + that.delBtnWidth + 'px';
}
}
//獲取手指觸摸的是哪一項
that.swiperData.txtStyle = txtStyle;
}
},
te(e) {
// 觸摸結束
let that = this;
if (e.changedTouches.length === 1) {
//手指移動結束後水平位置
let endX = e.changedTouches[0].clientX;
//觸摸開始與結束,是指移動的距離
let disX = that.startX - endX;
let delBtnWidth = that.delBtnWidth;
//如果距離小於刪除按鈕的1/2,不顯示刪除按鈕
let txtStyle =
disX > delBtnWidth / 2 ? 'left:-' + delBtnWidth + 'px' : 'left:0px';
//手指觸摸的是哪一項
that.swiperData.txtStyle = txtStyle;
}
},
del() {
// 刪除
}
};
events = {};
initEleWidth() {
let that = this;
that.delBtnWidth = that.getEleWidth(that.delBtnWidth);
console.log(that.delBtnWidth);
}
getEleWidth(w) {
//獲取元素自適應後的實際寬度(也就是根據設計稿寬度換算成px像素)
let real = 0;
try {
let resWidth = wx.getSystemInfoSync().windowWidth;
let scale = 750 / w;
real = Math.floor(resWidth / scale);
return real;
} catch (e) {
return false;
}
}
onLoad() {
this.initEleWidth();
}
}
</script>
<style lang="less">
.swiper-item-wrapper {
position: relative;
height: 100%;
overflow: hidden;
.swiper-content {
width: 100%;
height: 100%;
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
z-index: 5;
padding: 0 18rpx;
background-color: #fff;
}
.swiper-actions {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 140rpx;
height: 100%;
z-index: 1;
position: absolute;
top: 0;
&.actions-left {
left: 0;
}
&.actions-right {
right: 0;
}
}
.swiper-btn {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #ffffff;
&.del {
background-color: rgb(244, 51, 60);
}
&.edit {
background-color: rgb(16, 142, 233);
}
}
}
</style>
3.這裏是主頁面購物車頁面shop_cart.wpy
<template>
<view class="shop-cart">
<view class="good-list">
<repeat for="{{goods}}" key="item">
<swiperDel :swiperData.sync="item">
<view class="goods-info">
<icon class="icon_check" type="success" size="20" @tap.stop="selectList" data-index="{{index}}" wx:if="{{item.selected}}"></icon>
<icon class="icon_check" type="circle" size="20" @tap.stop="selectList" data-index="{{index}}" wx:else></icon>
<view class="img-box">
<image src="{{item.imgurl}}" class="img"/>
</view>
<view class="text-box">
<view class="goods-title">
{{item.name}}
</view>
<view class="lable">
<view class="price">
¥{{item.price}}</view>
<view class="shop-count">
<cartCount :good.sync="item" @getGood.user="getGood"></cartCount>
</view>
</view>
</view>
</view>
</swiperDel>
</repeat>
</view>
<view class="check-box">
<view class="left-price">
<view class="all-select-box" @tap.stop="selectAll">
<icon type="success" size="20" wx:if="{{judgeAllSelect}}"></icon>
<icon type="circle" size="20" wx:else></icon>
<text>全選</text>
</view>
<view class="total">
合計:¥{{totalPrice}}
</view>
</view>
<view class="pay-btn">去結算</view>
</view>
</view>
</template>
<script>
import wepy from 'wepy'
import swiperDel from '../components/swiper-delete'
import cartCount from '../components/cart-count'
export default class ShopCart extends wepy.page {
config = {
navigationBarTitleText: '購物車'
};
components = {
swiperDel,
cartCount
};
mixins = [];
data = {
allSelected: false,
goods: [
{
name: '新鮮蔬菜',
price: 5,
num: 2,
imgurl: ''
},
{
name: '素米500g',
price: 10,
num: 1,
imgurl: ''
},
{
name: '蘋果',
price: 20,
num: 5,
imgurl: ''
}
]
};
computed = {
totalPrice() { // 總價格
let that = this
let totalPrice = 0
for (let good of that.goods) {
if (good.selected) {
totalPrice += good.num * good.price
}
}
return totalPrice
},
judgeAllSelect() { //判斷全選
let that = this
let isAllSelected = that.goods.every((item) => { // 只要有一個沒選就爲false
return item.selected
})
isAllSelected ? (that.allSelected = true) : (that.allSelected = false)
return isAllSelected
}
}
methods = {
selectList(e) { // 當前勾選選中
let that = this
let curIndex = e.target.dataset.index // 獲取當前索
let curItem = that.goods[curIndex]
curItem.selected = !curItem.selected // 取反
},
selectAll(e) { // 全選
let that = this
that.allSelected = !that.allSelected
for (let good of that.goods) { // 商品每項選中的值和全選的狀態值一致
good.selected = that.allSelected
}
},
getGood (item) { // 自定義事件
// console.log(this.goods)
}
};
events = {};
onLoad() {
let that = this
that.goods.forEach((good) => { // 剛開始默認都是未選中狀態
good.selected = false
})
}
}
</script>
<style lang="less">
.good-list {
height: 150rpx;
.swiper-item-wrapper {
margin-bottom: 10rpx;
.swiper-content {
border-bottom: 1rpx solid #eeeeee;
.goods-info {
display: flex;
height: 150rpx;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
position: relative;
.icon_check {
position: absolute;
height: 100%;
width: 165rpx;
display: flex;
align-items: center;
}
.img-box {
background-color: pink;
width: 160rpx;
height: 100%;
margin-left: 100rpx;
.img {
width: 100%;
height: 100%;
}
}
.text-box {
width: 440rpx;
margin-left: 18rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.goods-title {
width: 100%;
font-size: 40rpx;
color: #000;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.lable {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 18rpx;
.price {
color: red;
}
.shop-count {
width: 164rpx;
height: 48rpx;
line-height: 48rpx;
}
}
}
}
}
}
}
.check-box {
display: flex;
justify-content: space-between;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 100rpx;
line-height: 100rpx;
padding-left: 18rpx;
border-top: 1px solid #eee;
background-color: #fff;
z-index: 999;
.left-price {
position: relative;
height: 100%;
display: flex;
justify-content: space-between;
margin-right: 18rpx;
flex: 1;
.all-select-box {
position: relative;
icon {
position: absolute;
height: 100%;
width: 165rpx;
display: flex;
align-items: center;
}
text {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
margin-left: 80rpx;
}
}
.total {
color: #e64340;
}
}
.pay-btn {
width: 240rpx;
text-align: center;
background: #e64340;
color: #ffffff;
font-size: 32rpx;
&.no-select {
background-color: #cccccc;
}
}
}
</style>
備註: 我將組件都放在src/components目錄下所以引用組件的時候都是import * from ‘../components/*‘,copy過去就可以跑起來,給大家看下我的目錄結構,結構圖如下