微信小程序實戰篇:商品屬性聯動選擇(案例)

IT實戰聯盟博客:http://blog.100boot.cn
微信小程序.jpg小程序

本期的微信小程序實戰篇來作一個電商網站常常用到的-商品屬性聯動選擇的效果,素材參考了一點點奶茶。
####效果演示:
商品屬性聯動.gif微信小程序

####代碼示例
#####一、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:提交校驗並獲取選中商品屬性結果。微信

#####二、commodity.js
數據結構markdown

//數據結構:以一組一組的數據來進行設定 
    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].attrValueList.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);
      }
    }
  }

結果提交xss

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);
    }
  }

#####三、commodity.wxsside

.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繪製移動報表佈局

####關注咱們
若是須要源碼能夠關注「IT實戰聯盟」衆*號並留言(源碼名稱+郵箱),小萌看到後會聯繫做者發送到郵箱,也能夠加入交流羣和做者互撩哦~~~flex

IT實戰聯盟博客:http://blog.100boot.cn