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

代码示例
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_list和weui-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. 调用系统的API,系统有提供下拉刷新的API接口 当然,你可以直接在全局变量app.json的window里面配置上面这个属性,这样整个项目都允许下 ...
- 前端微信小程序实战篇
电商底部导航栏的制作 我想大家对电商一定不陌生,一般电商的底部导航栏有以下几个首页.分类.购物车.个人中心. app.json是用来配置page路径以及导航栏属性的,那我们要做首页.分类.购物车.个人 ...
- 微信小程序实战篇:基于wxcharts.js绘制移动报表
前言 微信小程序图表插件(wx-charts)是基于canvas绘制,体积小巧,支持图表类型饼图.线图.柱状图 .区域图等图表图形绘制,目前wx-charts是微信小程序图表插件中比较强大好使的一个. ...
- 微信小程序实战篇-下拉刷新与加载更多
下拉刷新 实现下拉刷新目前能想到的有两种方式 1. 调用系统的API,系统有提供下拉刷新的API接口 2. 监听scroll-view,自定义下拉刷新,还记得scroll-view里面有一个binds ...
- 微信小程序实战篇-图片的预览、二维码的识别
开篇 今天,做的小程序项目要求,个人中心的客服图片在用户长按时可以识别其二维码,各种翻阅查找,采坑很多,浪费了很多时间,在这里记录下需要注意的点,以及对小程序官方提供的API做一个正确和清晰的认知,希 ...
- 微信小程序实战:表单与选择控件的结合
先上代码. login.wxml <mp-toptips msg="{{error}}" type="error" show="{{error} ...
- 微信小程序实战篇-电商(一)
我想大家对电商一定不陌生,一般电商的底部导航栏有以下几个首页.分类.购物车.个人中心.所以我们按照这个来做吧. app.json是用来配置page路径以及导航栏属性的,那我们要做首页.分类.购物车.个 ...
- 微信小程序实战篇-分类页面制作
https://blog.csdn.net/u012927188/article/details/73650264
- [转]微信小程序之购物车 —— 微信小程序实战商城系列(5)
本文转自:http://blog.csdn.net/michael_ouyang/article/details/70755892 续上一篇的文章:微信小程序之商品属性分类 —— 微信小程序实战商城 ...
随机推荐
- P1919 【模板】A*B Problem升级版(FFT快速傅里叶)
题目描述 给出两个n位10进制整数x和y,你需要计算x*y. 输入输出格式 输入格式: 第一行一个正整数n. 第二行描述一个位数为n的正整数x. 第三行描述一个位数为n的正整数y. 输出格式: 输出一 ...
- 解读人:林山云,Proteomic Identification of Protein Glutathionylation in Cardiomyocytes(心肌细胞蛋白质谷胱甘肽修饰的蛋白质组鉴定)
发表时间:(2019年4月) IF:3.950 单位:韦恩州立大学化学系 物种:小鼠心肌细胞 技术:谷胱甘肽修饰蛋白组学 一. 概述: 本研究采用化学选择性蛋白组学方法,鉴定出过氧化物诱导HL-1小鼠 ...
- Laplace(拉普拉斯)算子
[摘要] Laplace算子作为边缘检测之一,和Sobel算子一样也是工程数学中常用的一种积分变换,属于空间锐化滤波操作.拉普拉斯算子(Laplace Operator)是n维欧几里德空间中的一个二阶 ...
- [转载]sscanf函数
来源:http://c.biancheng.net/cpp/html/296.html 头文件:#include <stdio.h> sscanf()函数用于从字符串中读取指定格式的数据, ...
- Java类成员变量、普通成员变量、初始化块、构造方法的初始化和执行顺序
结论:执行的大致顺序如下, (1) 在一个不存在继承的类中:初始化static变量,执行static初始化块-->初始化普通成员变量(如果有赋值语句),执行普通初始化块-->构造方法 (2 ...
- P4245 【模板】任意模数NTT
Luogu4245 只要做三次的NTT,快的飞起 普通NTT,做9次 #include<cstdio> #include<cstring> #include<iostre ...
- JAVA Font类
java.awt.Font 设计字体显示效果 Font mf = new Font(String 字体,int 风格,int 字号); 字体:TimesRoman, Courier, Arial等 风 ...
- tomcat 普通用户报错方案
Tomcat Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 一眼就能看出来是jdk的环境有问题,但是用了 ...
- 免费的mysql数据库
https://blog.csdn.net/kernel_/article/details/53320498
- 使用Spring和JQuery实现视频文件的上传和播放
Spring MVC可以很方便用户进行WEB应用的开发,实现Model.View和Controller的分离,再结合Spring boot可以很方便.轻量级部署WEB应用,这里为大家介绍如何使用Spr ...