微信小程序购物车、父子组件传值及calc的注意事
前言
在做微信小程序时,觉得小组里对购物车的实现不是很完美,就自己尝试的写了下,然后用到了父子组件传值,父子组件传值的话,和vue框架上是非常相似的,以及calc这个css函数,calc有个注意点,自己不怎么用,一时间有差点忘了,这里记录下
狼蚁网站SEO优化话不多说了,来一起看看详细的介绍吧
1.效果图
2.子组件实现
要实现图中删除的效果,使用组件的形式更好做点,我当时本想直接在pages里实现,不过结果就是,滑动时,所有的商品都显示了删除按钮,除非用数组将每个商品要移动的距离存储起来,不过这样的话就很麻烦,所以我也是用组件来实现的
关于微信组件,可以直接点击链接访问官网查看
子组件index.wxml
<view class="modityItem" bindtouchstart="handleTouchStart" bindtouchmove="handleTouchMove" style="transform:translateX({{-rightSpace}}px)"> <view class="selectedBtn" bindtap="handleSelect" data-is-selected="{{modity.isselected}}"> <view class="noSelected" wx:if="{{modity.isselected==0}}"></view> <image class="selectedImg" wx:else src="/images/selected.png"></image> </view> <view class="modityInfo"> <view class="modityImg"> <image src="{{modity.image}}"></image> </view> <view class="modityTitle"> <view class="title">{{modity.title}}</view> <view class="standard">规格{{modity.standard?modity.standard:'无'}}</view> <view class="count"> <view class="price">¥{{modity.price}}</view> <view class="modityNum"> <i-input-number value="{{selectedNum}}" min="1" max="{{modity.stock}}" bindchange="numChange" /> </view> </view> </view> </view> <view class="deleteBtn"> <image class="deleteImg" src="/images/delete.png"></image> <text class="deleteText">删除</text> </view> </view>
子组件index.wxss
/ 商品 / .modityItem{ display: flex; position: relative; padding: 10rpx 24rpx 20rpx 30rpx; box-sizing: border-box; background: #fff; transition: all .5s; } / 选择按钮 / .selectedBtn{ display: flex; align-items: center; width: 80rpx; } .noSelected{ width: 46rpx; height: 46rpx; border-radius: 50%; border: 1px solid #ef5225; } .selectedBtn .selectedImg{ width: 50rpx; height: 50rpx; } / 商品信息 / .modityInfo{ display: flex; width: calc(100% - 80rpx); } .modityImg{ margin-right: 18rpx; width: 220rpx; height: 220rpx; } .modityImg image{ width: 100%; height: 100%; vertical-align: middle; } / 商品title / .modityTitle{ width: calc(100% - 220rpx); } .title{ display: -webkit-box; width: 100%; height: 70rpx; line-height:35rpx; font-size: 24rpx; font-weight:600; overflow: hidden; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } .standard{ padding-: 16rpx; width: 100%; height: 90rpx; box-sizing: border-box; } .count{ display: flex; align-items: center; justify-content: space-between; width: 100%; height: 60rpx; } / 删除按钮 / .deleteBtn{ display: flex; position: absolute; width: 70px; height: 100%; : 0rpx; right: -70px; flex-direction: column; align-items: center; justify-content: center; background: #ef5225; } .deleteImg{ margin-bottom: 10rpx; width: 50rpx; height: 50rpx; vertical-align: middle; } .deleteText{ color: #fff; }
子组件index.json,这里用了iview中的
{ "ponent": true, "usingComponents": { "i-input-number": "/ponent/iview/input-number/index" } }
子组件index.js
Component({ properties: { modity: Object, }, data: { touchStart: null, rightSpace: 0, selectedNum: 1, }, methods: { / 商品是否选中 / handleSelect() { let selectedNum = this.data.selectedNum; let modity = this.data.modity; if(modity.isselected == 0) { modity.isselected = 1; } else { modity.isselected = 0; } this.triggerEvent('handleselect', { modity, selectedNum}) }, / 处理触摸滑动开始 / handleTouchStart(e) { / 记录触摸滑动初始位置 / let touchStart = e.changedTouches[0].clientX; this.setData({ touchStart }) }, / 处理触摸滑动 / handleTouchMove(e) { console.log(e) let moveSpace = e.changedTouches[0].clientX; let touchStart = this.data.touchStart; if (touchStart != null) { if (moveSpace - touchStart > 70) { this.setData({ touchStart: null, rightSpace: 0 }) } else if (moveSpace - touchStart < -70) { this.setData({ touchStart: null, rightSpace: 70 }) } } }, numChange(e) { let selectedNum = e.detail.value; let modity = this.data.modity; this.setData({ selectedNum }) this.triggerEvent('handleselect', { modity, selectedNum}) } } })
3.父组件实现
父组件index.wxml,这里用的是假数据,所以操作上会有一些是联调时不必要的操作
<view class="cart"> <view class="item" wx:for="{{cartList}}" wx:key="{{items.shopid}}" wx:for-item="items"> <view class="storeInfo"> <image class="avatar" src="{{items.logo}}"></image> <view class="storeName">{{items.shopname}}</view> </view> <view class="discount">满¥100包邮,满10件包邮</view> <view class="modity" wx:for="{{items.modity}}" wx:key="{{item.id}}"> <cart-item modity="{{item}}" bind:handleselect="handleSelect" /> </view> </view> <view class="count"> <view class="selectAll" bindtap="handleSelectAll"> <view class="noSelected" wx:if="{{!isSelectedAll}}"></view> <image class="selectedImg" wx:else src="/images/selected.png"></image> <text class="selectAllText">全选</text> </view> <view class="countPrice"> <text>合计:</text> <text>¥{{countPrice}}</text> </view> <view class="aount"> <text>结算</text> <text>({{countSelectedNum}})</text> </view> </view> </view>
父组件index.wxss
page{ background: #f8f8f8; } .cart{ padding-bottom: 100rpx; font-size: 26rpx; } .item{ border-bottom: 1px solid #eee; } / 头部店铺信息 / .storeInfo{ display: flex; padding: 18rpx 0rpx 18rpx 30rpx; background: #fff; box-sizing: border-box; } .storeInfo .avatar{ width: 56rpx; height: 56rpx; border-radius: 50%; vertical-align: middle; } .storeInfo .storeName{ margin-left: 16rpx; line-height: 56rpx; } / 包邮信息 / .discount{ padding-left: 30rpx; height:50rpx; line-height: 50rpx; font-size:20rpx; color: #666; box-sizing: border-box; } / 底部操作 / .count{ display: flex; position: fixed; padding-left: 30rpx; bottom: 0; left: 0; width: 100%; height: 100rpx; line-height: 100rpx; box-sizing: border-box; color: #232323; background: #eee; } / 全选 / .selectAll{ display: flex; padding-right: 20rpx; align-items: center; width: 25%; font-size: 30rpx; } .selectAll .noSelected{ width: 46rpx; height: 46rpx; border-radius: 50%; border: 1px solid #ef5225; } .selectAll .selectedImg{ width: 50rpx; height: 50rpx; } .selectAllText{ margin-left: 18rpx; } .countPrice{ position: absolute; : 0; right: 270rpx; height: 100%; line-height: 100rpx; text-align: center; font-size: 30rpx; } .countPrice text{ margin-right: 15rpx; } .aount{ position: absolute; : 0; right: 0; width: 270rpx; height: 100%; line-height: 100rpx; text-align: center; font-size: 30rpx; background: #ef5225; color: #fff; } 父组件index.json,引用子组件 { "usingComponents": { "cart-item": "/ponent/cart/index" } }
父组件index.js
Page({ data: { cartList: [ { shopname: '猫咪小店', logo: '/images/avatar.jpeg', shopid: 11, modity: [ { id: 1, image:'/images/modity.jpg', title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊', standard: '111 + 黑色', price: '100', stock: 10, quantity: 1, isselected: 0, }, { id: 2, image:'/images/avatar7.jpg', title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊', price: '10', stock: 5, quantity: 1, isselected: 0, } ] }, { shopname: '猫咪小店', logo: '/images/avatar5.jpg', shopid: 450, modity: [ { id: 3, image:'/images/modity.jpg', title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊', price: '90', stock: 10, quantity: 1, isselected: 0, }, { id: 4, image:'/images/avatar7.jpg', title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊', price: '100', stock: 5, quantity: 1, isselected: 0, }, { id: 5, image:'/images/modity.jpg', title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊', standard: '111 + 黑色', price: '100', stock: 2, quantity: 1, isselected: 0, } ] }, { shopname: '猫咪小店', logo: '/images/avatar.jpeg', shopid: 550, modity: [ { id: 6, image:'/images/avatar8.jpg', title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊', standard: '111 + 黑色', price: '100', stock: 1, quantity: 1, isselected: 0, } ] }, ], / 商品是否全选中 / isSelectedAll: false, / 已选中商品的价格 / countPrice: 0, / 统计所有选中的商品数量 / countSelectedNum: 0, }, / 处理商品选中 / handleSelect(e) { let countPrice = 0; let countSelectedNum = 0; let cartList = this.data.cartList; let length = cartList.length; / 因为是假数据,所以需要循环查找到对应的数据将其替换 / for(let i = 0; i < length; i++) { for(let j = 0; j < cartList[i].modity.length; j++) { if (cartList[i].modity[j].id == e.detail.modity.id) { cartList[i].modity[j] = e.detail.modity; cartList[i].modity[j].selectedNum = e.detail.selectedNum; } if (cartList[i].modity[j].isselected == 1) { / 点击选中的时候,计算价格,要判断下设置的商品选中数量, 我这里的是对点击了的商品才设置了选中的数量,所以需要对没有点击的商品数量设置为1,然后就默认的加一 / if (cartList[i].modity[j].selectedNum != undefined) { countPrice += cartList[i].modity[j].price cartList[i].modity[j].selectedNum; countSelectedNum += cartList[i].modity[j].selectedNum } else { countPrice += cartList[i].modity[j].price 1; countSelectedNum += 1; } } } } / 对是否全选中进行判断 / let isSelectedAll = true; for (let i = 0; i < length; i++) { for (let j = 0; j < cartList[i].modity.length; j++) { / 若商品中的isselecetd有为0的就终止循环,直接设置为未全选 / if (cartList[i].modity[j].isselected == 0) { isSelectedAll = false; break; } } } this.setData({ cartList, isSelectedAll, countPrice, countSelectedNum }) }, / 全选中商品 / handleSelectAll() { let isSelectedAll = !this.data.isSelectedAll; let cartList = this.data.cartList; let length = cartList.length; let countPrice = 0; let countSelectedNum = 0; / 遍历数据中的isselected来进行全选的操作 / for(let i = 0; i < length; i++) { for (let j = 0; j < cartList[i].modity.length; j++) { if(isSelectedAll) { cartList[i].modity[j].isselected = 1; / 全选的时候,计算价格,要判断下设置的商品选中数量, 我这里的是对点击了的商品才设置了选中的数量,所以需要对没有点击的商品数量设置为1,然后就默认加一 / if (cartList[i].modity[j].selectedNum != undefined) { countPrice += parseInt(cartList[i].modity[j].price) cartList[i].modity[j].selectedNum; countSelectedNum += cartList[i].modity[j].selectedNum; } else { countPrice += cartList[i].modity[j].price 1; countSelectedNum += 1; } } else { cartList[i].modity[j].isselected = 0; } } } this.setData({ isSelectedAll, cartList, countPrice, countSelectedNum }) }, })
4.父子组件传值
较常用的都是父组件往子组件传值,所以子组件往父组件传值就会不是很熟悉
我这里的话,是因为用的假数据,在点击商品选中或者不选中时,需要改变商品里的选中属性,所以用到了子组件往父组件传值,也包括传递选中的商品数量
子组件往父组件传值的话,是通过在调用this.triggerEvent()来实现的
/ 在父组件中定义方法bind:handleselect或者也可以直接写成bindhandleselect/ <cart-item modity="{{item}}" bind:handleselect="handleSelect" />
在子组件中调用
this.triggerEvent('handleselect', { modity, selectedNum})
这个this.triggerEvent('handleselect', { modity, selectedNum })方法中,handleselect的名称要与父组件中引用子组件时绑定的方法名称一样,后面的对象就是传递的值,也可以直接是以直接量的形式传递,然后再父组件中通过e.detail来获取对应的值
handleSelect(e) { console.log(e.detail) console.log(e.detail.modity) console.log(e.detail.selectedNum) }
5.calc的注意事项
我以前也遇到过,然后现在再用的时候,一时间把这点给忘了,在看到编译器样式的时候,才猛然想起
.user-content{ padding: 10px 0 10px 50px; width: calc(100% - 50px); / 计算宽度,'+'或'-'符号前后有空格 / height: 18px; }
css中使用calc可以进行简单的运算
单位可以是百分比,px,rem,em等单位
使用"+","-","","/"运算符(使用"+"或者"-"符号时,符号前后必须加上空格)
在Firefox浏览器上使用要加上-moz前缀
chrome浏览器上使用要加上-webkit前缀
(使用"+"或者"-"符号时,符号前后必须加上空格)
6.部分想法
其实在样式上还是挺快就完成了,就是在计算商品价格的时候,想了挺久
在计算价格时,当时就有点蒙圈,总是想着要怎么判断他是增加数量还是减少数量,然后就陷入死循环的之中。
其实不用想她是增加还是减少数量,因为你都是传的是商品的数量,而且在计算时,也是判断了商品是否选中,所以,直接点,计算价格乘以数量就可以了
然后选中的商品数量的统计就和计算价格的思路是一样的了
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对狼蚁SEO的支持。
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程