由于公司开发了一个电商项目,涉及到前台商品属性的展示,所以百度上找了一下!找到了 周琪力写的一个算法例子,因为作者只有jQuery 实现demo, 自己仿照 demo 实现了一个 vue 的!

周琪力原文: http://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247484853&idx=1&sn=bed59c1d83c3aeb4bf7881be8dbdd917&chksm=97236777a054ee61fc3cef07eb4b164fa28e26917ce0a409d876964ad3c2ee3f90a000e29beb#rd

原文的demo实现:http://codepen.io/keelii/pen/RoOzgb

效果图: 

附上代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 实现商品属性的计算显示</title>
<style>
body {
font-size: 12px;
}
dt {
width: 100px;
text-align: right;
}
dl {
clear: both;
overflow:hidden;
}
dl.hl {
background:#ddd;
}
dt, dd {
float:left;
height: 40px;
line-height: 40px;
margin-left: 10px;
}
button {
font-size: 14px;
font-weight: bold;
width: 100px;
height: 30px;
margin: 0 10px;
} .disabled {
color:#999;
border: 1px dashed #666;
}
.active {
color: red;
} .top-but {
margin: 10px;
} #skuId {
height: 24px;
font-size: 14px;
line-height: 24px;
}
</style>
</head>
<body>
<textarea id="values" style="width:600px;height:100px">
[
{ "颜色": "红", "尺码": "大", "型号": "A", "skuId": "3158055" },
{ "颜色": "白", "尺码": "大", "型号": "A", "skuId": "3158054" },
{ "颜色": "白", "尺码": "中", "型号": "B", "skuId": "3133859" },
{ "颜色": "蓝", "尺码": "小", "型号": "C", "skuId": "3516833" }
]
</textarea>
<div id="app">
<label>
默认选中 :
<input type="text" name="skuId" id="skuId" v-bind:value="skuId">
</label>
<button @click="getTextareaData" class="top-but"> 重新加载数据 </button> 当前属性ID:{{ skuId }}
<dl v-for="item, key in list.result" class="content" v-bind:class="{hl: highKeys[key]}">
<dt> {{key}} : </dt>
<dd>
<button
class="item"
v-for="value in item"
@click="handleActive(key, value)"
v-bind:class="{active: value.active, disabled: !value.active && value.disabled}"
> {{ value.name }} </button>
</dd>
</dl>
已经选择:{{ message }}
</div>
</body>
<script src="https://unpkg.com/vue "></script>
<script>
let vue = new Vue({
el: "#app",
data(){
return {
data: [],
skuId: "",
skuName: "skuId",
// 属性名称信息
keys: [],
// 数据集合{list.result list.items}
list: {},
// 分隔符
spliter: '\u2299',
result: {},
message: "",
highKeys: {},
};
},
methods: {
powerset(arr) {
let ps = [[]];
for (let i = 0; i < arr.length; i++) {
for (let j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(arr[i]));
}
} return ps;
}, /**
* 初始化数据
* @return
*/
initData() {
this.result = {};
this.keys = this.getAllKeys();
for (let i = 0; i < this.keys.length; i ++) {
this.highKeys[this.keys[i]] = false;
} this.list = this.combineAttr(this.data, this.keys);
this.initSeleted(this.skuId);
this.buildResult(this.list.items)
this.updateStatus(this.getSelectedItem());
this.showResult();
}, /**
* 获取输入表单中的数据进行初始化
* @return
*/
getTextareaData() {
let data = document.getElementById('values').value;
let skuId = document.getElementById("skuId").value; try {
this.data = JSON.parse(data);
let isHas = false;
for (let i = 0; i < this.data.length; i ++) {
if (skuId == this.data[i][this.skuName]) {
isHas = true;
break
}
} this.skuId = isHas ? skuId : this.data[0][this.skuName];
this.initData();
} catch (e) {
this.data = [];
}
}, /**
* 正常属性点击
*/
handleNormalClick(key, value) {
for (let i in this.list.result[key]) {
if (i != value.name) {
this.list.result[key][i].active = false;
} else {
this.list.result[key][i].active = true;
}
}
}, /**
* 无效属性点击
*/
handleDisableClick(key, value) {
this.list.result[key][value.name]["disabled"] = false;
// 清空高亮行的已选属性状态(因为更新的时候默认会跳过已选状态)
for (let i in this.list.result) {
if (i != key) {
for (let x in this.list.result[i]) {
this.list.result[i][x].active = false;
}
}
} this.updateStatus(this.getSelectedItem());
}, /**
* 高亮行
*/
highAttributes: function() {
for (let key in this.list.result) {
this.highKeys[key] = true;
for (let attr in this.list.result[key]) {
if (this.list.result[key][attr].active === true) {
this.highKeys[key] = false;
break;
}
}
}
}, /**
* 点击事件处理
* @param key 点击的行
* @param value 点击的按钮的数据
*/
handleActive: function(key, value) {
if (value.active == true) {
return false;
} this.handleNormalClick(key, value);
if (value.disabled === true) {
this.handleDisableClick(key, value);
} this.updateStatus(this.getSelectedItem());
this.highAttributes();
this.showResult();
}, /**
* 计算属性
* @param {[type]} data [description]
* @param {[type]} keys [description]
* @return {[type]} [description]
*/
combineAttr(data, keys) {
let allKeys = []
let result = {} for (let i = 0; i < data.length; i++) {
let item = data[i]
let values = [] for (let j = 0; j < keys.length; j++) {
let key = keys[j]
if (!result[key]) {
result[key] = {};
} if (!result[key][item[key]]) {
result[key][item[key]] = {"name": item[key], "active": false, "disabled": true};
} values.push(item[key]);
} allKeys.push({
path: values.join(this.spliter),
sku: item['skuId']
});
} return {
result: result,
items: allKeys
}
}, /**
* 获取所有属性
* @return {[type]} [description]
*/
getAllKeys() {
let arrKeys = [];
for (let attribute in this.data[0]) {
if (!this.data[0].hasOwnProperty(attribute)) {
continue;
} if (attribute !== this.skuName) {
arrKeys.push(attribute);
}
} return arrKeys;
}, getAttruites(arr) {
let result = []
for (let i = 0; i < arr.length; i++) {
result.push(arr[i].path)
} return result
}, /**
* 生成所有子集是否可选、库存状态 map
*/
buildResult(items) {
let allKeys = this.getAttruites(items) for (let i = 0; i < allKeys.length; i++) {
let curr = allKeys[i];
let sku = items[i].sku;
let values = curr.split(this.spliter);
let allSets = this.powerset(values); // 每个组合的子集
for (let j = 0; j < allSets.length; j++) {
let set = allSets[j]
let key = set.join(this.spliter) if (this.result[key]) {
this.result[key].skus.push(sku)
} else {
this.result[key] = {
skus: [sku]
}
}
}
}
}, /**
* 获取选中的信息
* @return Array
*/
getSelectedItem() {
let result = [];
for (let attr in this.list.result) {
let attributeName = '';
for (let attribute in this.list.result[attr]) {
if (this.list.result[attr][attribute].active === true) {
attributeName = attribute;
}
} result.push(attributeName);
} return result
}, /**
* 更新所有属性状态
*/
updateStatus(selected) {
for (let i = 0; i < this.keys.length; i++) {
let key = this.keys[i],
data = this.list.result[key],
hasActive = !!selected[i],
copy = selected.slice(); for (let j in data) {
let item = data[j]["name"];
if (selected[i] == item) {
continue
} copy[i] = item
let curr = this.trimSpliter(copy.join(this.spliter), this.spliter);
this.list.result[key][j]["disabled"] = this.result[curr] ? false : true;
}
}
}, trimSpliter(str, spliter) {
// ⊙abc⊙ => abc
// ⊙a⊙⊙b⊙c⊙ => a⊙b⊙c
let reLeft = new RegExp('^' + spliter + '+', 'g');
let reRight = new RegExp(spliter + '+$', 'g');
let reSpliter = new RegExp(spliter + '+', 'g');
return str.replace(reLeft, '')
.replace(reRight, '')
.replace(reSpliter, spliter)
}, /**
* 初始化选中
* @param mixed|Int|String skuId 需要选中的skuId
* @return {[type]} [description]
*/
initSeleted(skuId) {
for (let i in this.data) {
if (this.data[i][this.skuName] == skuId) {
for (let x in this.data[i]) {
if (x !== this.skuName) {
this.list.result[x][this.data[i][x]].active = true;
}
}
break;
}
}
}, /**
* 显示选中的信息
* @return
*/
showResult() {
let result = this.getSelectedItem()
let s = []
for (let i = 0; i < result.length; i++) {
let item = result[i];
if (!!item) {
s.push(item)
}
} if (s.length == this.keys.length) {
let curr = this.result[s.join(this.spliter)]
if (curr) {
s = s.concat(curr.skus)
this.skuId = curr.skus[0];
} this.message = s.join('\u3000-\u3000');
}
}
}, created() {
this.getTextareaData();
}
})
</script>
</html>

前端如何展示商品属性:SKU多维属性状态判断算法的应用-Vue 实现的更多相关文章

  1. SKU多维属性状态判断算法

    作者:周琪力,前端工程师,网络常用昵称「keelii」.在过去的4年里主要负责京东网站商品详情页的前端系统架构和开发,平时主要写 JavaScript 偶尔写点NodeJS,Python.琪力博客:  ...

  2. 瑞联科技:Pwp3框架 调用存储过程返还数据集合 到前端界面展示

    一:代码结构: 1:Js 代码结构 2:Java 代码结构 二:前端界面展示效果 为了数据安全性:界面数据做了处理 三:全端代码展示 1:main.vop <html> <head& ...

  3. 循序渐进VUE+Element 前端应用开发(14)--- 根据ABP后端接口实现前端界面展示

    在前面随笔<循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理>简单的介绍了一个结合ABP后端的登陆接口实现前端系统登陆的功能,本篇随笔继续深化这一主 ...

  4. 商品模型:SPU、商品、SKU概念模型设计

    商品系统是电商SaaS.新零售SaaS最基础.最核心的系统之一.商品系统几乎需要支撑所有业务系统,商品详情.购物车.订单.履约.结算.售后.库存.供应链等,都需要依赖商品系统的能力.为了保障业务的稳定 ...

  5. 前端优秀作品展示,JavaScript 版水果忍者

    <水果忍者>是一款非常受喜欢的手机游戏,刚看到新闻说<水果忍者>四周年新版要上线了.网页版的切水果游戏由百度 JS 小组开发,采用 vml + svg 绘图,使用了 Rapha ...

  6. 总结:从Node爬取数据到前端图表展示

    最近寒假在家学习Node.js开发,光看书或者跟着敲代码还不够,得找一点有趣的事情来玩一玩,于是我决定写一个Node爬虫,爬取一些有意思或者说是有用的数据.这个决定只与我的兴趣有关,与Python或者 ...

  7. base64编码后的pdf文件前端页面展示--pdf.js的应用

    最近在整理项目中用到的插件或者使用心得,感觉还是写成博客,能加深新一层的理解. 我先说一下我的需求:由于java后台编译的文件流在手机端加载速度太慢,所以想着可以在前端解析,放在页面展示给用户. 所以 ...

  8. python 之 前端开发(CSS三大特性、字体属性、文本属性、背景属性)

    11.38 css三大特性 11.381 继承性 1.定义:给某一个元素设置一些属性,该元素的后代也可以使用,这个我们就称之为继承性​2.注意:    1.只有以color.font-.text-.l ...

  9. 前端MVC Vue2学习总结(九)——Vuex状态管理插件

    一.概要 1.1.Vuex定义与注意事项 Vuex是为vue.js框架更好的管理状态而设计一个插件.Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的 ...

随机推荐

  1. 16.1113 模拟考试T3

    城堡[问题描述]给定一张N个点M条边的无向连通图,每条边有边权.我们需要从M条边中选出N − 1条, 构成一棵树. 记原图中从 1 号点到每个节点的最短路径长度为?Di ,树中从 1 号点到每个节点的 ...

  2. python3.6安装遇到的问题

    Ubuntu16.04版本最新的Python 3.x版本3.5 . 可以从源代码执行安装最新稳定版本3.6. 要安装Python 3.6 ,请运行以下命令: # wget https://www.py ...

  3. AC日记——美元汇率 洛谷 P1988

    题目背景 此处省略maxint+1个数 题目描述 在以后的若干天里戴维将学习美元与德国马克的汇率.编写程序帮助戴维何时应买或卖马克或美元,使他从100美元开始,最后能获得最高可能的价值. 输入输出格式 ...

  4. MySql 初始化权限脚本

    刚装好MySql后无法用客户端工具连接,通过命令行登录后,运行下面的脚本: GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'     IDENTIFIED BY 'y ...

  5. 切换横屏幕 onCreate 多次执行问题

    在AndroidManifest.xml 中activity 中添加 android:configChanges="orientation|screenSize|smallestScreen ...

  6. js 中 Map/Set 集合

      Map Map是一组键值对的结构,具有极快的查找速度. 举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array: 1 var names = ['Michael', ...

  7. ivy在eclipse中的重新加载

    ivy在eclipse中的重新加载 如果由于网速的原因,导致了ivy没有正常的加载,可以进行ivy的重新加载: 1,右键点击项目,选择属性->Java Build Path->Librat ...

  8. memchached你知道和不知道的事

  9. C#语言基础语句

    case,switch,break的使用 Console.WriteLine("1.汉堡"); Console.WriteLine("2.薯条"); Conso ...

  10. navicat-premium11.1.6 x64关键

    Navicat Premium version patch   11.2.16.0 >navicat.exe0000000001CECCBC:80->C60000000001CECCBD: ...