您当前的位置: 首页 > 解决方案

微信小程序之购物车和父子组件传值及calc的注意事项

  • 作者: admin
  • 发布于 2019-01-15 14:14:34
  • 来源:  
  • 栏目:解决方案

导语: 1.效果图 2.子组件实现 要实现图中删除的效果,使用组

 

1.效果图

26.jpg

2.子组件实现

  • 要实现图中删除的效果,使用组件的形式更好做点,我当时本想直接在pages里实现,不过结果就是,滑动时,所有的商品都显示了删除按钮,除非用数组将每个商品要移动的距离存储起来,不过这样的话就很麻烦,所以我也是用组件来实现的
  • 关于微信组件,可以直接点击链接访问官网查看自定义组件
  • 子组件index.wxml
<view class="commodityItem" bindtouchstart="handleTouchStart" bindtouchmove="handleTouchMove" style="transform:translateX({{-rightSpace}}px)">   <view class="selectedBtn" bindtap="handleSelect" data-is-selected="{{commodity.isselected}}">     <view class="noSelected" wx:if="{{commodity.isselected==0}}"></view>     <image class="selectedImg" wx:else src="/images/selected.png"></image>   </view>   <view class="commodityInfo">     <view class="commodityImg">       <image src="{{commodity.image}}"></image>               </view>     <view class="commodityTitle">       <view class="title">{{commodity.title}}</view>       <view class="standard">规格:{{commodity.standard?commodity.standard:'无'}}</view>       <view class="count">         <view class="price">{{commodity.price}}</view>         <view class="commodityNum">           <i-input-number value="{{selectedNum}}" min="1" max="{{commodity.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
/* 商品 */ .commodityItem{   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; } /* 商品信息 */ .commodityInfo{   display: flex;   width: calc(100% - 80rpx); } .commodityImg{   margin-right: 18rpx;   width: 220rpx;   height: 220rpx; } .commodityImg image{   width: 100%;   height: 100%;   vertical-align: middle;   } /* 商品title */ .commodityTitle{   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-top: 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%;   top: 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; }
{   "component": true,   "usingComponents": {     "i-input-number": "/component/iview/input-number/index"   } }
  • 子组件index.js
Component({    properties: {     commodity: Object,   },    data: {     touchStart: null,     rightSpace: 0,     selectedNum: 1,   },    methods: {     /* 商品是否选中 */     handleSelect() {             let selectedNum = this.data.selectedNum;       let commodity = this.data.commodity;       if(commodity.isselected == 0) {         commodity.isselected = 1;       } else {         commodity.isselected = 0;       }             this.triggerEvent('handleselect', { commodity, 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 commodity = this.data.commodity;         this.setData({             selectedNum         })         this.triggerEvent('handleselect', { commodity, 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="commodity" wx:for="{{items.commodity}}" wx:key="{{item.id}}">       <cart-item commodity="{{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="account">       <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;   top: 0;   right: 270rpx;   height: 100%;   line-height: 100rpx;   text-align: center;   font-size: 30rpx; } .countPrice text{   margin-right: 15rpx; } .account{   position: absolute;   top: 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": "/component/cart/index"   } }
  • 父组件index.js
Page({    data: {     cartList: [       {         shopname: '猫咪小店',         logo: '/images/avatar.jpeg',         shopid: 11,         commodity: [           {             id: 1,             image:'/images/commodity.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,         commodity: [           {             id: 3,             image:'/images/commodity.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/commodity.jpg',             title: '雅诗兰黛鲜活焕亮红石榴晚霜50ml 补水保湿 滋润排浊',             standard: '111 + 黑色',             price: '100',             stock: 2,             quantity: 1,             isselected: 0,           }         ]       },       {         shopname: '猫咪小店',         logo: '/images/avatar.jpeg',         shopid: 550,         commodity: [           {             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].commodity.length; j++) {                 if (cartList[i].commodity[j].id == e.detail.commodity.id) {           cartList[i].commodity[j] = e.detail.commodity;           cartList[i].commodity[j].selectedNum = e.detail.selectedNum;         }         if (cartList[i].commodity[j].isselected == 1) {           /* 点击选中的时候,计算价格,要判断下设置的商品选中数量,            * 我这里的是对点击了的商品才设置了选中的数量,所以需要对没有点击的商品数量设置为1,然后就默认的加一            */           if (cartList[i].commodity[j].selectedNum != undefined) {             countPrice += cartList[i].commodity[j].price * cartList[i].commodity[j].selectedNum;             countSelectedNum += cartList[i].commodity[j].selectedNum           } else {             countPrice += cartList[i].commodity[j].price * 1;             countSelectedNum += 1;           }         }       }     }          /* 对是否全选中进行判断 */         let isSelectedAll = true;         for (let i = 0; i < length; i++) {             for (let j = 0; j < cartList[i].commodity.length; j++) {                 /* 若商品中的isselecetd有为0的就终止循环,直接设置为未全选 */                 if (cartList[i].commodity[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].commodity.length; j++) {                 if(isSelectedAll) {                     cartList[i].commodity[j].isselected = 1;           /* 全选的时候,计算价格,要判断下设置的商品选中数量,            * 我这里的是对点击了的商品才设置了选中的数量,所以需要对没有点击的商品数量设置为1,然后就默认加一            */           if (cartList[i].commodity[j].selectedNum != undefined) {             countPrice += parseInt(cartList[i].commodity[j].price) * cartList[i].commodity[j].selectedNum;             countSelectedNum += cartList[i].commodity[j].selectedNum;           } else {             countPrice += cartList[i].commodity[j].price * 1;                 countSelectedNum += 1;                   }                 } else {                     cartList[i].commodity[j].isselected = 0;                 }             }         }          this.setData({             isSelectedAll,             cartList,       countPrice,       countSelectedNum         })     }, })

4.父子组件传值

  • 较常用的都是父组件往子组件传值,所以子组件往父组件传值就会不是很熟悉
  • 我这里的话,是因为用的假数据,在点击商品选中或者不选中时,需要改变商品里的选中属性,所以用到了子组件往父组件传值,也包括传递选中的商品数量
  • 子组件往父组件传值的话,是通过在调用this.triggerEvent()来实现的
/* 在父组件中定义方法:bind:handleselect或者也可以直接写成bindhandleselect*/ <cart-item commodity="{{item}}" bind:handleselect="handleSelect" />
  • 在子组件中调用
this.triggerEvent('handleselect', { commodity, selectedNum})
这个this.triggerEvent('handleselect', { commodity, selectedNum })方法中,handleselect的名称要与父组件中引用子组件时绑定的方法名称一样,后面的对象就是传递的值,也可以直接是以直接量的形式传递,然后再父组件中通过e.detail来获取对应的值
handleSelect(e) {     console.log(e.detail)     console.log(e.detail.commodity)     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.部分想法

  • 其实在样式上还是挺快就完成了,就是在计算商品价格的时候,想了挺久
  • 在计算价格时,当时就有点蒙圈,总是想着要怎么判断他是增加数量还是减少数量,然后就陷入死循环的之中。
  • 其实不用想她是增加还是减少数量,因为你都是传的是商品的数量,而且在计算时,也是判断了商品是否选中,所以,直接点,计算价格乘以数量就可以了
  • 然后选中的商品数量的统计就和计算价格的思路是一样的了
正在努力学习中,若对你的学习有帮助,留下你的印记呗(点个赞咯^_^)



温馨提示:这篇文章没有解决您的问题?欢迎添加微信:18948083295,有微信小程序专业人员,保证有问必答。转载本站文章请注明转自http://www.okeydown.com/(微信小程序网)。

  • 微信扫描二维码关注官方微信
  • ▲长按图片识别二维码
关注我们

微信小程序官方微信

栏目最新
栏目推荐
返回顶部