前言

做电商项目呢,离不开多规格商品,SKU 也是弄了许久才搞出来,主要是多层级的联动关系,用ID和库存来判断是否是按钮禁止状态

下面就放下代码:

以封装的小程序为例:

WXML:

<view class="sku-box" wx:if="{{cpSkuTree.length}}">
<view class="sku-row" wx:for="{{cpSkuTree}}" wx:key="{{index}}">
<view class="sku-title">{{item.k}}</view>
<view class="sku-wrap flex-row">
<view class="sku-item {{iitem.disabled ? 'disabled': ''}} {{iitem.selected ? 'selected': ''}}" wx:for="{{item.v}}" wx:for-item="iitem" wx:for-index="iindex" wx:key="{{iindex}}" data-index="{{index}}" data-iindex="{{iindex}}" data-k="{{item}}" data-value="{{iitem}}" catchtap="selectSku">{{iitem.name}}</view>
</view>
</view>
</view>

JS:

const computedBehavior = require('miniprogram-computed')

Component({
behaviors: [computedBehavior],
properties: {
skuTree: {
type: Array,
value: [],
observer: function (newVal) {
let cpNewVal = JSON.parse(JSON.stringify(newVal))
cpNewVal.forEach( row => {
row.v.forEach(item => {
Object.assign(item, {
selected: false,
disabled: false
})
})
})
this.setData({
cpSkuTree: cpNewVal
})
this.judgeAllItem()
}
},
skuList: {
type: Array,
value: []
}
},
data: {
cpSkuTree: [],
// 选择的 sku 组合
selectedSku: {
}
},
computed: { },
methods: {
// 点击sku按钮
selectSku (e) {
const k = e.currentTarget.dataset.k
const index = e.currentTarget.dataset.index
const value = e.currentTarget.dataset.value
const iindex = e.currentTarget.dataset.iindex
value.disabled = true
if (this.data.cpSkuTree[index].v[iindex].disabled) {
return
}
// 勾选或者反选
const key = `selectedSku.${k.ks}`
if (!this.data.cpSkuTree[index].v[iindex].selected) {
// 勾选把值记住
this.setData({
[key]: value.id
})
} else {
// 反选把值删掉
this.setData({
[key]: ''
})
}
this.setData({
[`cpSkuTree[${index}].v[${iindex}].selected`]: !this.data.cpSkuTree[index].v[iindex].selected
})
this.cancelOption(index, value)
this.judgeAllItem()
this.changePic(index, iindex)
if (this.isAllSelected()) {
const skuData = this.getSkuComb()
this.triggerEvent('selectChange', skuData)
} else {
this.triggerEvent('selectChange', null)
}
},
/**
* 取消同一组所有选项
*/
cancelOption (index, value) {
let rowList = this.data.cpSkuTree[index].v
for (let i = 0; i < rowList.length; i++) {
if (rowList[i].id != value.id) {
this.setData({
[`cpSkuTree[${index}].v[${i}].selected`]: false
})
}
}
},
/**
* 循环判断是否可选
*/
judgeAllItem () {
let tree = this.data.cpSkuTree
for (let i = 0; i < tree.length; i++) {
let v = tree[i].v
for (let j = 0; j < v.length; j++) {
if (this.isSkuChoosable(tree[i].ks, v[j].id)) {
this.setData({
[`cpSkuTree[${i}].v[${j}].disabled`]: false
})
} else {
this.setData({
[`cpSkuTree[${i}].v[${j}].disabled`]: true
})
}
}
}
this.getSelectedText()
},
/**
* 判断可选项的库存
*/
isSkuChoosable (ks, id) {
const list = this.data.skuList
const selectedSku = this.data.selectedSku
// 先假设已经选中剩余按钮
let matchedSku = Object.assign({}, selectedSku, {
[ks]: id
}) // 将matchedSku中有效的key提取
let skusToCheck = Object.keys(matchedSku).filter(
skuKey => matchedSku[skuKey] != ''
)
// 有效key值匹配有多少sku
let filterSku = list.filter(sku =>
skusToCheck.every(
skuKey => matchedSku[skuKey] == sku[skuKey]
)
)
// 假设按钮包含所有sku的库存数
let stock = filterSku.reduce((total, sku) => {
total += sku.stock_num
return total
}, 0)
return stock > 0 },
/**
* 判断是否选完所有规格
*/
isAllSelected () {
let selectedSku = this.data.selectedSku
let selected = Object.keys(selectedSku).filter(
skuKey => selectedSku[skuKey] !== ''
)
return selected.length === this.data.cpSkuTree.length
},
/**
* 获得已经确定的组合
*/
getSkuComb () {
let selectedSku = this.data.selectedSku
let list = this.data.skuList
let skusToCheck = []
this.data.cpSkuTree.forEach(item => {
skusToCheck.push(item.ks)
})
let filteredSku = list.filter(sku => (
skusToCheck.every(skuKey => selectedSku[skuKey] == sku[skuKey])
)
)
return filteredSku[0]
},
/**
* 修改图片
*/
changePic (index, iindex) {
if (index == 0) {
this.triggerEvent('changePic', this.data.cpSkuTree[index].v[iindex].picUrl)
}
},
// 选择属性文字
getSelectedText () {
let selectedSku = this.data.selectedSku
let text = ''
Object.keys(selectedSku).forEach(skuKey => {
const id = selectedSku[skuKey]
const tree = this.data.cpSkuTree
for (let i = 0; i < tree.length; i++) {
const v = tree[i].v
for (let j = 0; j < v.length; j++) {
if (v[j].id == id) {
text = `${text} ${v[j].name}`
}
}
}
})
this.triggerEvent('textChange', text)
}
}
})

上面都有注释:

CSS

.flex-row {
display: flex;
flex-direction: row;
} .flex-col {
display: flex;
flex-direction: column;
}
.sku-box {
width: 100%;
background: #fff;
padding: 40rpx;
}
.sku-row {
margin-bottom: 36rpx;
}
.sku-title {
color: #333;
font-size: 24rpx;
line-height:;
}
.sku-wrap {
margin-top: 36rpx;
flex-wrap: wrap;
}
.sku-item {
min-width: 160rpx;
padding: 18rpx 14rpx;
color: #555555;
font-size: 24rpx;
line-height:;
border-radius: 4rpx;
background: #EAEAEA;
border: 1rpx solid #EAEAEA;
text-align: center;
margin-bottom: 20rpx;
}
.sku-item+.sku-item {
margin-left: 24rpx;
}
.sku-item.disabled {
color: #ababab;
}
.sku-item.selected {
color: #38ADFF;
background:rgba(56,173,255,0.1);
border: 1rpx solid #38ADFF;
}

然后封装使用在 父组件使用,

这个就是效果图,

嘻嘻 这样就算封装完毕

多规格商品SKU 组件封装的更多相关文章

  1. 商品sku规格选择效果,没有商品的不能选中,选择顺序不影响展示结果

    <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...

  2. vue+element 实现商品sku效果

    在网上搜索了很久,没有发现合适sku编辑的文章,只能自己写一个vue+element 的sku编辑功能.实现的效果如下图 除成本.售价.库存.货号这几个写死的属性外,可自行添加/删除商品属性,自行添加 ...

  3. jquery实现商品sku多属性选择(商品详情页)

    转载于https://blog.csdn.net/csdn924618338/article/details/51455595 实现效果 源码 <!DOCTYPE HTML> <ht ...

  4. 循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

    VUE+Element 前端应用,比较不错的一点就是界面组件化,我们可以根据重用的指导方针,把界面内容拆分为各个不同的组合,每一个模块可以是一个组件,也可以是多个组件的综合体,而且这一个过程非常方便. ...

  5. B2C电子商务系统研发——商品SKU分析和设计(二)

    转:http://www.cnblogs.com/winstonyan/archive/2012/01/07/2315886.html 上文谈到5种商品SKU设计模式,本文将做些细化说明. 笔者研究过 ...

  6. Vuejs 页面的区域化与组件封装

    组件的好处 当我用vue写页面的时候,大量的数据页面渲染,引入组件简化主页面的代码量,当代码区域块代码差不多相同时,组件封装会更加简化代码.组件是Vue.js最强大的功能之一. 组件可以扩展HTML元 ...

  7. ReactNative之从HelloWorld中看环境搭建、组件封装、Props及State

    开篇呢,先给大家问个好,今天是中秋节,祝大家中秋节快乐!!虽然是中秋节,但是木有回家还是总结一下知识点写写博客吧,想着昨天总结一下的,但是昨天和几个同学小聚了一下,酒逢知己总是千杯少呢,喝的微醺不适合 ...

  8. Vue + Element UI 实现权限管理系统 (功能组件封装)

    组件封装 为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度. 组件结构 组件封装重构后,试图组件结构如下图所示 代码一览 Home组件被简化,包含导航.头部和主内容三个组 ...

  9. Vue + Element UI 实现权限管理系统 前端篇(七):功能组件封装

    组件封装 为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度. 组件结构 组件封装重构后,试图组件结构如下图所示 代码一览 Home组件被简化,包含导航.头部和主内容三个组 ...

随机推荐

  1. python-Re模块用法

    主要函数:match().search().compile() re.compile compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 se ...

  2. Django初步完成:登录、注册、退出

    python环境:python2.7 开发工具:pycharm 项目名称:mysite5 app名称:online settings:映射app路径 INSTALLED_APPS = [ 'djang ...

  3. Spectral Norm Regularization for Improving the Generalizability of Deep Learning论文笔记

    Spectral Norm Regularization for Improving the Generalizability of Deep Learning论文笔记 2018年12月03日 00: ...

  4. 【原创】Java基础之Nginx缓存

    1 proxy_ignore_headers 1.1 Set-Cookie By default, nginx does not caches requests with Set-Cookie. 默认 ...

  5. ZROI Day1 比赛解题报告

    ZROI Day1 比赛解题报告 版权原因不提供题面相关信息 序 前天晚上搞得比较晚,然后早上做题很没状态,刚看到T1发现没什么思路就有点慌,赶紧看了看T2,T3, 发现T3暴力很好打,T2想了一想可 ...

  6. css高度居中

    1.已知元素高度 // 子盒子 #div1{ width:200px; height:200px; position: absolute; //父元素需要相对定位 top: 50%; left: 50 ...

  7. ubuntu根目录下空间不足,syslog占用很大空间,如何清理?

    一激动差点儿删除,以下清理方式是对的 cat /dev/null > /var/log/syslog

  8. IntelliJ IDEA 接口类跳转到实现类及实现类跳转到接口

    接口和实现类的互相跳转是使用IntelliJ IDEA过程中常用的操作,在此记录一下: 1.Service接口跳转到实现类 操作:在接口类的方法上使用快捷键Ctrl+Alt+B,或者点击下图所示位置 ...

  9. centos 7 firewall(防火墙)开放端口/删除端口/查看端口

    1.firewall的基本启动/停止/重启命令 复制#centos7启动防火墙 systemctl start firewalld.service #centos7停止防火墙/关闭防火墙 system ...

  10. python中F/f表达式优于format()表达式

    F/f表达式可以解析任意类型的数据 具体实现,看下面示例: 1.解析变量 1 a = 10 3 b = 20 5 res1 = F"a+b的值:{a+b}" 7 print(res ...