多规格商品SKU 组件封装
前言
做电商项目呢,离不开多规格商品,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 组件封装的更多相关文章
- 商品sku规格选择效果,没有商品的不能选中,选择顺序不影响展示结果
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- vue+element 实现商品sku效果
在网上搜索了很久,没有发现合适sku编辑的文章,只能自己写一个vue+element 的sku编辑功能.实现的效果如下图 除成本.售价.库存.货号这几个写死的属性外,可自行添加/删除商品属性,自行添加 ...
- jquery实现商品sku多属性选择(商品详情页)
转载于https://blog.csdn.net/csdn924618338/article/details/51455595 实现效果 源码 <!DOCTYPE HTML> <ht ...
- 循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码
VUE+Element 前端应用,比较不错的一点就是界面组件化,我们可以根据重用的指导方针,把界面内容拆分为各个不同的组合,每一个模块可以是一个组件,也可以是多个组件的综合体,而且这一个过程非常方便. ...
- B2C电子商务系统研发——商品SKU分析和设计(二)
转:http://www.cnblogs.com/winstonyan/archive/2012/01/07/2315886.html 上文谈到5种商品SKU设计模式,本文将做些细化说明. 笔者研究过 ...
- Vuejs 页面的区域化与组件封装
组件的好处 当我用vue写页面的时候,大量的数据页面渲染,引入组件简化主页面的代码量,当代码区域块代码差不多相同时,组件封装会更加简化代码.组件是Vue.js最强大的功能之一. 组件可以扩展HTML元 ...
- ReactNative之从HelloWorld中看环境搭建、组件封装、Props及State
开篇呢,先给大家问个好,今天是中秋节,祝大家中秋节快乐!!虽然是中秋节,但是木有回家还是总结一下知识点写写博客吧,想着昨天总结一下的,但是昨天和几个同学小聚了一下,酒逢知己总是千杯少呢,喝的微醺不适合 ...
- Vue + Element UI 实现权限管理系统 (功能组件封装)
组件封装 为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度. 组件结构 组件封装重构后,试图组件结构如下图所示 代码一览 Home组件被简化,包含导航.头部和主内容三个组 ...
- Vue + Element UI 实现权限管理系统 前端篇(七):功能组件封装
组件封装 为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度. 组件结构 组件封装重构后,试图组件结构如下图所示 代码一览 Home组件被简化,包含导航.头部和主内容三个组 ...
随机推荐
- Flutter与Xamarin跨平台移动开发相比
在过去十年中,移动行业经历了巨大的增长,特别是在应用程序开发方面.据Statista报告称,全球智能手机用户超过20亿,预计到2022年底这一数字将增加到50亿以上.在这些智能手机中,近100%在三个 ...
- static char定义的用法
static char *p是全局静态变量,char *p是临时变量,static定义的你在其他地方可以调用,而且是通用的,也就是说你在一个地方改了它的值,其他地方也就跟着改了,而char *p只是一 ...
- 了解WebSocket
了解WebSocket WebSocket协议是基于TCP的一种新的协议.WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符.它实现了浏览器与服务器全 ...
- Elastic Search 分布式架构分析
1 ES分布式机制的透明隐藏特性ES本身就是一个分布式系统,就是为了处理海量数据的应用.ES隐藏了复杂的分布式机制,简化了配置和操作的复杂度.ES在现在的互联网环境中,盛行的原因,主要的核心就是分布式 ...
- Java Web ClassLoader工作机制
一.ClassLoader的作用: 1.类加载机制:父优先的等级加载机制 2.类加载过程 3.将Class字节码重新解析成JVM统一要求的对象格式 二.ClassLoader常用方法 1.define ...
- Sharepoint 开启App 配置App
如果没有Enable app,打开app store的时候出出现错误: Sorry, apps are turned off. If you know who runs the server, tel ...
- centos配置发送邮件
邮件已经可以接收到了 CentOS下发送邮件有很多种方法,这里采用比较简单的mail客户端,配置第三方邮件服务商,例如:163.com 1.安装所用软件 yum install mailx sendm ...
- svn的一些使用技巧
新项目的目录结构说明: 代码分三部分 1.01_Trunk(开发主干) 2.02_Branches(开发分支) 3.03_Tags(提交代码区) 文档区 请注意SVN的路径是区分大小写的! 与VSS的 ...
- element-ui 表单自定义日期输入校验
methods: { validateDate(rule, value, callback){ if (value) { let timestamp = new Date(value).getTime ...
- OLE使用
ABAP操作EXCEL有多重方法,今天记录一下OLE,具体步骤如下: 1. 首先要上载EXCEL模板 事物代码:SMW0,具体步骤参考 本博客 http://www.cnblogs.com/caizj ...