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

效果演示:

 
商品属性联动.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].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);
      }
    }
  }

结果提交

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

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

作者:IT实战联盟Lin
链接:https://www.jianshu.com/p/f7f5f593b8e3
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

微信小程序实战篇:商品属性联动选择(案例)的更多相关文章

  1. 【微信小程序】转载:微信小程序实战篇-下拉刷新与加载更多

    下拉刷新 实现下拉刷新目前能想到的有两种方式 1. 调用系统的API,系统有提供下拉刷新的API接口 当然,你可以直接在全局变量app.json的window里面配置上面这个属性,这样整个项目都允许下 ...

  2. 前端微信小程序实战篇

    电商底部导航栏的制作 我想大家对电商一定不陌生,一般电商的底部导航栏有以下几个首页.分类.购物车.个人中心. app.json是用来配置page路径以及导航栏属性的,那我们要做首页.分类.购物车.个人 ...

  3. 微信小程序实战篇:基于wxcharts.js绘制移动报表

    前言 微信小程序图表插件(wx-charts)是基于canvas绘制,体积小巧,支持图表类型饼图.线图.柱状图 .区域图等图表图形绘制,目前wx-charts是微信小程序图表插件中比较强大好使的一个. ...

  4. 微信小程序实战篇-下拉刷新与加载更多

    下拉刷新 实现下拉刷新目前能想到的有两种方式 1. 调用系统的API,系统有提供下拉刷新的API接口 2. 监听scroll-view,自定义下拉刷新,还记得scroll-view里面有一个binds ...

  5. 微信小程序实战篇-图片的预览、二维码的识别

    开篇 今天,做的小程序项目要求,个人中心的客服图片在用户长按时可以识别其二维码,各种翻阅查找,采坑很多,浪费了很多时间,在这里记录下需要注意的点,以及对小程序官方提供的API做一个正确和清晰的认知,希 ...

  6. 微信小程序实战:表单与选择控件的结合

    先上代码. login.wxml <mp-toptips msg="{{error}}" type="error" show="{{error} ...

  7. 微信小程序实战篇-电商(一)

    我想大家对电商一定不陌生,一般电商的底部导航栏有以下几个首页.分类.购物车.个人中心.所以我们按照这个来做吧. app.json是用来配置page路径以及导航栏属性的,那我们要做首页.分类.购物车.个 ...

  8. 微信小程序实战篇-分类页面制作

    https://blog.csdn.net/u012927188/article/details/73650264

  9. [转]微信小程序之购物车 —— 微信小程序实战商城系列(5)

    本文转自:http://blog.csdn.net/michael_ouyang/article/details/70755892 续上一篇的文章:微信小程序之商品属性分类  —— 微信小程序实战商城 ...

随机推荐

  1. dedecms图片绝对路径(附件绑定域名)的设置方法

    dedecms默认的附件路径使用的是相对路径,但是在实际应用,我们可能会需要让文章的图片附件显示绝对地址,解决方案如下: 1.打开include目录下的文件extend.func.php,添加函数re ...

  2. StampedLock原理

    原文链接:https://blog.csdn.net/sunhaoning/article/details/68924625 StamppedLock是Java 8中引入的一种新的锁机制.读写锁虽然分 ...

  3. DP【洛谷P2363】马农

    [洛谷P2363]马农 题目描述 在观看完战马检阅之后,来自大草原的两兄弟决心成为超级"马农",专门饲养战马. 兄弟两回到草原,将可以养马的区域,分为N*N的单位面积的正方形,并实 ...

  4. kuangbin专题十二 HDU1087 Super Jumping! Jumping! Jumping! (LIS)

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  5. Qt 学习之路 2(1):序

    https://www.devbean.net/category/qt-study-road-2/page/10 原来开过QT学习之路1, 很棒, 再翻阅时已经没有了. 所以这次把看过的记录下来 Ho ...

  6. [Java]如何把Soap Message装成一个String对象

    代码片段 // Create transformer TransformerFactory tff = TransformerFactory.newInstance(); Transformer tf ...

  7. Mybatis学习笔记(九) —— Mybatis逆向工程

    一.什么是Mybatis逆向工程? 简单的解释就是通过数据库中的单表,自动生成java代码. 我们平时在使用Mabatis框架进行Web应用开发的过程中,需要根据数据库表编写对应的Pojo类和Mapp ...

  8. 小a与黄金街道(欧拉函数+快速幂)

    链接:https://ac.nowcoder.com/acm/contest/317/D 来源:牛客网 题目描述 小a和小b来到了一条布满了黄金的街道上.它们想要带几块黄金回去,然而这里的城管担心他们 ...

  9. NowCoder数列(矩阵快速幂变式)

    时间限制 3000 ms 内存限制 32768 KB 代码长度限制 100 KB 题目描述 NowCoder最近在研究一个数列: * F(0) = 7 * F(1) = 11 * F(n) = F(n ...

  10. logback日志简记

    %date{HH:mm:ss.SSS} [%thread] %-5level %logger{20}:%line - %msg%n 输出: 09:54:09.657 [main] INFO  c.e. ...