微信小程序实战篇:商品属性联动选择(案例)

西域战神 2018-03-28 13:43:34 ⋅ 182 阅读


本期的微信小程序实战篇来做一个电商网站经常用到的-商品属性联动选择的效果,素材参考了一点点奶茶。

效果演示:

商品属性联动.gif

代码示例

1、commodity.xml
<!-- <view class="title">属性值联动选择</view>   -->
<!--options-->
<view class="commodity_attr_list">    <!--每组属性-->    <view class="attr_box" wx:for="{{attrValueList}}" wx:for-item="attrValueObj" wx:for-index="attrIndex">      <!--属性名-->      <view class="attr_name">{{attrValueObj.attrKey}}</view>          <!--属性值-->      <view class="attr_value_box">          <!--每个属性值-->          <view class="attr_value {{attrIndex==firstIndex || attrValueObj.attrValueStatus[valueIndex]?(value==attrValueObj.selectedValue?'attr_value_active':''):'attr_value_disabled'}}" bindtap="selectAttrValue" data-status="{{attrValueObj.attrValueStatus[valueIndex]}}"          data-value="{{value}}" data-key="{{attrValueObj.attrKey}}" data-code="{{attrCode}}" data-index="{{attrIndex}}" data-selectedvalue="{{attrValueObj.selectedValue}}" wx:for="{{attrValueObj.attrValues}}" wx:for-item="value" wx:for-index="valueIndex">{{value}}</view>      </view>  </view>
</view>
<!--button-->
<view class="weui-btn-area">    <button class="weui-btn" bindtap="submit">选好了       </button>
</view>

上述代码把页面盒子分为两部分commodity_attr_listweui-btn-area
commodity_attr_list:循环获取商品的属性名和相对应的属性值,并布局页面。
weui-btn-area:提交校验并获取选中商品属性结果。

2、commodity.js

数据结构

    //数据结构:以一组一组的数据来进行设定 
    commodityAttr: [
      {
        priceId: 1,
        price: 35.0,        
       "stock": 8,        
       "attrValueList": [          {            
           "attrKey": "规格:",            
           "attrValue": "+免费配料",            
           "attrCode": "1001"          },          {            
           "attrKey": "甜度:",            
           "attrValue": "七分甜",            
           "attrCode": "2001"          },          {            
           "attrKey": "加料:",            
           "attrValue": "珍珠",            
           "attrCode": "3001"          },          {            
           "attrKey": "冰块:",            
           "attrValue": "少冰",            
           "attrCode": "4001"          }        ]      },      {        priceId: 2,        price: 35.1,        
           "stock": 9,        
           "attrValueList": [          {            
           "attrKey": "规格:",            
           "attrValue": "+燕麦",            
           "attrCode": "1002"          },          {            
           "attrKey": "甜度:",            
           "attrValue": "五分甜",            
           "attrCode": "2002"          },          {            
           "attrKey": "加料:",            
           "attrValue": "椰果",            
           "attrCode": "3002"          },          {            
           "attrKey": "冰块:",            
           "attrValue": "去冰",            
           "attrCode": "4002"          }        ]      },      {        priceId: 3,        price: 35.2,        
           "stock": 10,        
           "attrValueList": [          {            
           "attrKey": "规格:",            
           "attrValue": "+布丁",            
           "attrCode": "1003"          },          {            
           "attrKey": "甜度:",            
           "attrValue": "无糖",            
           "attrCode": "2003"          },          {            
           "attrKey": "加料:",            
           "attrValue": "仙草",            
           "attrCode": "3003"          },          {            
           "attrKey": "冰块:",            
           "attrValue": "常温",            
           "attrCode": "4003"          }        ]      },      {        priceId: 4,        price: 35.2,        
       "stock": 10,        
       "attrValueList": [          {            
           "attrKey": "规格:",            
           "attrValue": "再加一份奶霜",            
           "attrCode": "1004"          },          {            
           "attrKey": "甜度:",            
           "attrValue": "无糖",            
           "attrCode": "2003"          },          {            
           "attrKey": "加料:",            
           "attrValue": "仙草",            
           "attrCode": "3004"          },          {            
           "attrKey": "冰块:",            
           "attrValue": "热饮",            
           "attrCode": "4004"          }        ]      },      {        priceId: 5,        price: 35.2,        
       "stock": 10,        
       "attrValueList": [          {            
           "attrKey": "规格:",            
           "attrValue": "+免费配料",            
           "attrCode": "1004"          },          {            
           "attrKey": "甜度:",            
           "attrValue": "五分甜",            
           "attrCode": "2003"          },          {            
           "attrKey": "加料:",            
           "attrValue": "椰果",            
           "attrCode": "3004"          },          {            
           "attrKey": "冰块:",            
           "attrValue": "常温",            
           "attrCode": "4004"          }        ]      }    ],    attrValueList: []  }

属性选中和取消选择效果处理

onShow: function () {    
   this.setData({      
       includeGroup: this.data.commodityAttr    });    
   this.distachAttrValue(this.data.commodityAttr);    
   // 只有一个属性组合的时候默认选中    // console.log(this.data.attrValueList);    if (this.data.commodityAttr.length == 1) {      
       for (var i = 0; i < this.data.commodityAttr[0].attrValue                    List.length; i++) {        
           this.data.attrValueList[i].selectedValue = this.data.commodityAttr[0].attrValueList[i].attrValue;      }      
   this.setData({        
       attrValueList: this.data.attrValueList      });    }  },  
/* 获取数据 */distachAttrValue: function (commodityAttr) {    
   /**    将后台返回的数据组合成类似    {    attrKey:'型号',    attrValueList:['1','2','3']    }    */    // 把数据对象的数据(视图使用),写到局部内    var attrValueList = this.data.attrValueList;    
   // 遍历获取的数据    for (var i = 0; i < commodityAttr.length; i++) {      
   for (var j = 0; j < commodityAttr[i].attrValueList.length; j++) {        
       var attrIndex = this.getAttrIndex(commodityAttr[i].attrValueList[j].attrKey, attrValueList);        
       // console.log('属性索引', attrIndex);        // 如果还没有属性索引为-1,此时新增属性并设置属性值数组的第一个值;索引大于等于0,表示已存在的属性名的位置        if (attrIndex >= 0) {          
       // 如果属性值数组中没有该值,push新值;否则不处理          if (!this.isValueExist(commodityAttr[i].attrValueList[j].attrValue, attrValueList[attrIndex].attrValues)) {            attrValueList[attrIndex].attrValues.push(commodityAttr[i].attrValueList[j].attrValue);          }        } else {          attrValueList.push({            
           attrKey: commodityAttr[i].attrValueList[j].attrKey,
           attrValues: [commodityAttr[i].attrValueList[j].attrValue]          });        }      }    }    
   // console.log('result', attrValueList)    for (var i = 0; i < attrValueList.length; i++) {      
       for (var j = 0; j < attrValueList[i].attrValues.length; j++) {        
           if (attrValueList[i].attrValueStatus) {              attrValueList[i].attrValueStatus[j] = true;            } else {              attrValueList[i].attrValueStatus = [];              attrValueList[i].attrValueStatus[j] = true;            }          }    }    
   this.setData({      
       attrValueList: attrValueList    });  },  
 getAttrIndex: function (attrName, attrValueList) {    
   // 判断数组中的attrKey是否有该属性值    for (var i = 0; i < attrValueList.length; i++) {      
       if (attrName == attrValueList[i].attrKey) {        
           break;      }    }    
       return i < attrValueList.length ? i : -1;  },  
 isValueExist: function (value, valueArr) {    
   // 判断是否已有属性值  for (var i = 0; i < valueArr.length; i++) {      
   if (valueArr[i] == value) {        
       break;      }    }    
   return i < valueArr.length;  },  
 /* 选择属性值事件 */  selectAttrValue: function (e) {    
   /*    点选属性值,联动判断其他属性值是否可选    {    attrKey:'型号',    attrValueList:['1','2','3'],    selectedValue:'1',    attrValueStatus:[true,true,true]    }    console.log(e.currentTarget.dataset);    */    var attrValueList = this.data.attrValueList;    
   var index = e.currentTarget.dataset.index;
   //属性索引    var key = e.currentTarget.dataset.key;    
   var value = e.currentTarget.dataset.value;    
   if (e.currentTarget.dataset.status || index == this.data.firstIndex) {      
       if (e.currentTarget.dataset.selectedvalue == e.currentTarget.dataset.value) {        
           // 取消选中            this.disSelectValue(attrValueList, index, key, value);        } else {        
           // 选中        this.selectValue(attrValueList, index, key, value);      }    }  },  
 /* 选中 */  selectValue: function (attrValueList, index, key, value, unselectStatus) {    
     // console.log('firstIndex', this.data.firstIndex);      var includeGroup = [];    
     if (index == this.data.firstIndex && !unselectStatus) {
     // 如果是第一个选中的属性值,则该属性所有值可选      var commodityAttr = this.data.commodityAttr;      
     // 其他选中的属性值全都置空      // console.log('其他选中的属性值全都置空', index, this.data.firstIndex, !unselectStatus);      for (var i = 0; i < attrValueList.length; i++) {        
     for (var j = 0; j < attrValueList[i].attrValues.length; j++) {          attrValueList[i].selectedValue = '';        }      }    } else {      
     var commodityAttr = this.data.includeGroup;    }    
   // console.log('选中', commodityAttr, index, key, value);    for (var i = 0; i < commodityAttr.length; i++) {      
   for (var j = 0; j < commodityAttr[i].attrValueList.length; j++) {        
   if (commodityAttr[i].attrValueList[j].attrKey == key && commodityAttr[i].attrValueList[j].attrValue == value) {          includeGroup.push(commodityAttr[i]);        }      }    }    attrValueList[index].selectedValue = value;    
   // 判断属性是否可选    for (var i = 0; i < attrValueList.length; i++) {      
   for (var j = 0; j < attrValueList[i].attrValues.length; j++) {        attrValueList[i].attrValueStatus[j] = false;      }    }    
   for (var k = 0; k < attrValueList.length; k++) {      
       for (var i = 0; i < includeGroup.length; i++) {        
           for (var j = 0; j < includeGroup[i].attrValueList.length; j++) {          
           if (attrValueList[k].attrKey == includeGroup[i].attrValueList[j].attrKey) {            
               for (var m = 0; m < attrValueList[k].attrValues.length; m++) {              
               if (attrValueList[k].attrValues[m] == includeGroup[i].attrValueList[j].attrValue) {                attrValueList[k].attrValueStatus[m] = true;              }            }          }        }      }    }    
   // console.log('结果', attrValueList);    this.setData({      
       attrValueList: attrValueList,      
       includeGroup: includeGroup    });    
   var count = 0;    
   for (var i = 0; i < attrValueList.length; i++) {      
       for (var j = 0; j < attrValueList[i].attrValues.length; j++) {        
       if (attrValueList[i].selectedValue) {          count++;          
         break;        }      }    }    
   if (count < 2) {
     // 第一次选中,同属性的值都可选      this.setData({        
         firstIndex: index      });    } else {      
         this.setData({        
             firstIndex: -1      });    }  },  
 /* 取消选中 */  disSelectValue: function (attrValueList, index, key, value) {    
 var commodityAttr = this.data.commodityAttr;    attrValueList[index].selectedValue = '';    
 // 判断属性是否可选    for (var i = 0; i < attrValueList.length; i++) {      
     for (var j = 0; j < attrValueList[i].attrValues.length; j++) {        attrValueList[i].attrValueStatus[j] = true;      }    }    
   this.setData({      
       includeGroup: commodityAttr,      
       attrValueList: attrValueList    });    
   for (var i = 0; i < attrValueList.length; i++) {      
   if (attrValueList[i].selectedValue) {        
       this.selectValue(attrValueList, i, attrValueList[i].attrKey, attrValueList[i].selectedValue, true);      }    }  }

结果提交

submit: function () {    
var value = [];    
for (var i = 0; i < this.data.attrValueList.length; i++) {      
if (!this.data.attrValueList[i].selectedValue) {        
   break;      }      value.push(this.data.attrValueList[i].selectedValue);    }    
if (i < this.data.attrValueList.length) {      wx.showToast({        
       title: '请选择完整!',        
       icon: 'loading',        
       duration: 1000      })    } else {      
var valueStr = "";      
for(var i = 0;i < value.length;i++){        
console.log(value[i]);        valueStr += value[i]+",";      }      wx.showModal({        
           title: '提示',        
           content: valueStr,        
           success: function (res) {          
           if (res.confirm) {            
               console.log('用户点击确定')          } else if (res.cancel) {            
               console.log('用户点击取消')          }        }      })        console.log(valueStr);    }  }
3、commodity.wxss
.title { 
 padding: 10rpx 20rpx; 
 margin: 10rpx 0; 
 border-left: 4rpx solid #ccc; 
} 
  /*全部属性的主盒子*/.commodity_attr_list { 
 background: #fff; 
 padding: 0 20rpx; 
 font-size: 26rpx; 
 overflow: hidden; 
 width: 100%; 
} 
/*每组属性的主盒子*/.attr_box { 
 width: 100%; 
 overflow: hidden; 
 border-bottom: 1rpx solid #ececec; 
 display: flex; flex-direction: column;
} 
/*属性名*/.attr_name { 
 width: 20%; 
 float: left; 
 padding: 15rpx 0; 
} 
/*属性值*/.attr_value_box { 
 width: 80%; 
 float: left; 
 padding: 15rpx 0; 
 overflow: hidden; 
} 
/*每个属性值*/.attr_value { 
 float: left; 
 padding: 0 30rpx; 
 margin: 10rpx 10rpx; 
 border: 1rpx solid #ececec; 
 border-radius:5px; line-height:30px;
} 
/*每个属性选中的当前样式*/.attr_value_active { 
 border-radius: 10rpx; 
 color: #0089dc; 
 padding: 0 30rpx; 
 border: 1rpx solid #0089dc; 
 /* background: #fff;   */} 
/*禁用属性*/.attr_value_disabled { 
 color: #ccc; 
} 
  /*button*/.weui-btn-area { 
 margin: 1.17647059em 15px 0.3em; 
} 
.weui-btn{  
 width: 80%;  
 height: 100rpx;  
 border-radius: 3rpx;  background-color:#0089dc;  color: #fff; }

好了,复制上述代码就可以实现效果哦,赶紧试试吧!

更多精彩内容

微信小程序电商实战-入门篇
微信小程序电商实战-首页(上)
微信小程序电商实战-首页(下)
微信小程序电商实战-商品详情(上)
微信小程序电商实战-商品列表流式布局
微信小程序实战篇:基于wxcharts.js绘制移动报表

小程序实战-幸运大转盘

微信小程序-Image的widthFix属性和rpm尺寸的使用

关注我们

如果需要源码可以关注“IT实战联盟”公众号并留言(源码名称+邮箱),小萌看到后会联系作者发送到邮箱,也可以加入交流群和作者互撩哦~~~




全部评论: 0

    我有话说:

    程序实现商品数量加减

    这是一个用程序原生代码实现的数量加减demo,主要是用于商品购物车或者商品详情修改数量使用

    程序商城(七):动态API实现商品分类

    程序商品分类页面布局并且调用动态API获取数据并加载

    程序电商实战-商品详情(上)

    先看一下今天要实现程序商品详情页吧!

    程序电商实战-商品列表流式布局

    今天给大家分享一下程序商品列表的流式布局方式,根据文章内容操作就可以看到效果哦~~~

    程序-Image的widthFix属性和rpm尺寸的使用

    在做程序商品详情页,商品的详情是图片集合,渲染完成后发现图片加载的很不自然

    程序商城(四):动态API实现商品详情页(上)

    1、实现商品详情页面布局(这实现3个模块,头部商品图片轮播、商品价格和商品描述、商品详情展示) 2、根据用户点击不同的商品请求API动态加载数据

    程序商城(九):授权并实现个人中心页面页面

    实现商城授权并获取用户信息和个人中心页面布局

    程序电商实战-首页(下)

    上一程序电商实战-首页(上)好了,上一期我们把首页搜索、导航栏和广告轮播给做完了,那么接下来会继续

    程序电商实战-首页(上)

    上一程序电商实战-入门 嗨,大家好!经过近两周的精心准备终于开始程序电商实战之路喽。那么最终会做成什么样呢?好了,不啰嗦了 我们先看首页长什么样吧!   首页效果图

    程序商城(八):缓存实现商品购物车功能

    商品详情页将商品信息放入缓存,购物车页面读取缓存获取商品信息,购物车商品计算和删除缓存商品

    程序实战:基于wxcharts.js绘制移动报表

    程序图表插件(wx-charts)是基于canvas绘制,体积巧,支持图表类型饼图、线图、柱状图 ......

    程序商城(五):动态API实现商品详情页(下)

    加入购物车悬浮框、商品数量、价格计算、收藏和加入购物车功能开发

    程序电商实战-入门

    程序开发工具有新版本更新啦!开发体验更好了,接下来一起为电商程序做一下准备前期准备工作~~

    程序-template使用:实现购物车商品数量加减功能

    上一我们实现了购物车功能,里面有用到template模板功能来实现购物车商品数量加减和价格计算功能......

    程序实战:如何解决https域名问题 ?

    开发自己的程序绕不开https问题,为了能在程序中调用我们自己的API服务请打开看一看吧!!!

    程序电商实战-商品详情加入购物车(下)

    今天会接着上一开始写商品详情页加入购物车的部分,直接看效果......

    程序抖音实战-首页(上)

    你也可以用程序编写一个抖音

    程序商城(六):动态API实现新品特卖商品流式布局

    实现新品特卖商品列表布局、调用动态API获取数据并加载和点击商品跳转商品详情

    程序实战程序之页面数据传递

    我们在写程序的时候经常会遇到子页面向主页面回传数据或者普通页面跳转到tabBar 页面携带数......