1. 效果图
数据格式
{
"id": 2,
"title": "林间有风自营针织衫",
"subtitle": "秋日冬款,浪漫满屋",
"category_id": 12,
"root_category_id": 2,
"price": "77.00",
"img": "http://i1.sleeve.7yue.pro/assets/ecf8d824-19d4-4db2-a5da-872ab014fecd.png",
"for_theme_img": "https://gitee.com/lrelia7/sleeve-static/raw/master/theme/spu1.png",
"description": null,
"discount_price": "62.00",
"tags": "秋日冬款$浪漫满屋",
"is_test": true,
"online": true,
"sku_list": [{
"id": 2,
"price": 77.76,
"discount_price": null,
"online": true,
"img": "http://i1.sleeve.7yue.pro/assets/2d22ffec-b1c1-43e0-ad21-25aa5c26ab34.png",
"title": "金属灰·七龙珠",
"spu_id": 2,
"category_id": 17,
"root_category_id": 3,
"specs": [{
"key_id": 1,
"key": "颜色",
"value_id": 45,
"value": "金属灰"
}, {
"key_id": 3,
"key": "图案",
"value_id": 9,
"value": "七龙珠"
}, {
"key_id": 4,
"key": "尺码",
"value_id": 14,
"value": "小号 S"
}],
"code": "2$1-45#3-9#4-14",
"stock": 5
}],
"spu_img_list": [{
"id": 165,
"img": "http://i1.sleeve.7yue.pro/assets/5605cd6c-f869-46db-afe6-755b61a0122a.png",
"spu_id": 2
}],
"spu_detail_img_list": [{
"id": 24,
"img": "http://i2.sleeve.7yue.pro/n4.png",
"spu_id": 2,
"index": 1
}],
"sketch_spec_id": 1,
"default_sku_id": 2
}
2. Lin-UI组件
Lin-UI Grid组件文档
3. 实现思路
3.1. 将数据中的规格与规格值过滤出来
3.2 使用Lin-UI的l-grid与l-grid-item组件遍历规格与规格值来实现列表
- 将规格值得id来充当l-grid-item的key
- 设置点击事件, 可获取当前点击的规格值id
// 点击事件
getGrid: function(e) {
const valueId = e.detail.key
if (this.data.disable.indexOf(parseInt(valueId)) === -1) {
return;
}
// 选中/反选
const selects = this._select(valueId);
// 禁用
const disable = this._disable(selects);
this.setData({
selects,
disable
});
},
3.3 使用wxs与三元运算符实现默认/选中/禁用不同的样式
3.3.1 选中/反选
- 声明两个数组 select 数组与 disable数组
- 当select数组中有对应规格值id时表示当前规格值已选中
- 每次点击时触发事件将当前规格值id放入select数组中, 反选时再将当前规格值id移除
- 同规格的规格值时只能选择一个
/**
* 选中/反选
* @param valueId
* @returns {Array}
* @private
*/
_select(valueId) {
const selects = this.data.selects; //选中数组
let specDisables= this.data.specDisables;
//找出valueId所在的规格id分组
let ds = [];
for (var spec of specDisables) {
if (spec.indexOf(parseInt(valueId)) > -1) {
ds = ds.concat(spec);
}
}
// 判断已选中的数组中是否有 valueId的同组规格id 如果有则删除select数组的规格值id
for (var d of ds) {
if (selects.indexOf(d.toString()) > -1 && d !== parseInt(valueId)) {
selects.splice(this._arrays(d, selects), 1);
}
}
if (selects.indexOf(valueId) === -1) { //如果当前规格id不存在 添加
selects.push(valueId);
return selects;
}
selects.splice(this._arrays(valueId, selects), 1); //如果存在 删除
return selects;
},
3.3.2 禁用
- disable数组默认有所有规格值id, 当规格值id不存在时禁用
- 不能点击, 每次进入点击事件时判断disable数组中是否有当前点击的规格值id, 如果不存在直接return
- 每次点击时触发事件通过select数组中已选中的规格值id来筛选出可用的规格值, 并放入到disable数组中
/**
* 禁用
* @param selects
* @returns {Array}
* @private
*/
_disable(selects) {
let skuDisables = this.data.skuDisables;
let specDisables= this.data.specDisables;
let disables = [];
let disable = [];
if (selects.length === 0) {
disable = this.data.specValueIds;
}
for (var se of selects) {
let ds = [];
for (var sku of skuDisables) {
if (sku.indexOf(parseInt(se)) > -1) {
ds = ds.concat(sku);
}
}
for (var spec of specDisables) {
if (spec.indexOf(parseInt(se)) > -1) {
ds = ds.concat(spec);
}
}
disables.push(ds);
}
console.log(disables);
for (var dis of disables) {
if (disable.length === 0) {
disable = dis;
continue;
}
disable = this._intersect(disable,dis); //交集
}
return disable;
},
看这个之前先去项目中观察完整的数据格式 jsonData
- 获取到数据时把 数据按照每个sku与不同的规格分别进行分组( 例如 [45, 9, 14]是一组规格值id组成的一个sku. [45, 42, 42, 44]是所有规格id为1的规格值id )
- 当选中规格值为45时, 从sku的分组来看包含45的分组为[45, 9, 14] 从规格分组来看( 同种规格 ) 包含45的是[45, 42, 42, 44] 所以可选规格值为[45, 9, 14, 42, 44]
- 当选中规格值为45, 14时, 同理包含14的sku分组[44,8,14]和[45, 9, 14] 规格分组[14, 15, 16, 14] 因为45与14规格值要同时满足才是可选状态所以要取交集并去重得出可选规格值[45, 14, 9, 44]
4. wxml代码
{{item.key}}
{{spec.value}}
5. wxs代码
module.exports.disable = function(disableSpecs, valueId){
return disableSpecs.indexOf(valueId) === -1
}
module.exports.includes = function(selectSpecs, spec) {
return selectSpecs.indexOf(spec.toString()) > -1;
}
5. 代码地址
https://gitee.com/winnxudong/lin_lessons