利用tire实现带无库存标注的规格选择思路 只是思路没有实现
数据格式
一般数据结构就是这种
抽象出来最基本的数据类型就是一个多维数组
[[30,40,50,60], [“电动车”, “电脑”, “驾照”]]
没有库存
但麻烦的是有的sku库存为0,比如要实现这种ui样式;
“红色/8G/i5“和“红色/8G/i7“的库存为0,在选择了“红色“和“8G“后“cpu的i5和i7”就要变灰色不能再选了;
选择和“红色”和“i5”后8G也不能再选了。
笛卡尔积
做笛卡尔积就包含了所有的规格属性值组合的sku;
后台接口一般会把做好笛卡尔积的所有sku列表已字典的形式返回;
{
"红色/4G/i3":"库存0",
"红色/4G/i5":"库存99",
...
}
前端需要根据用户交互选择的前两个规格禁用掉第三个属性的规格,根据前一个禁用后两个,甚至是全部禁用。
一年多前写过一个带库存的规格选择,现在回头看完全不知道写了写什么。https://blog.csdn.net/weixin_42519137/article/details/89294904
也没有参考意义了
利用前缀tire
前些阵子用tire做了一个站内导航
https://www.yuque.com/wuzhao/kb/wgo04g
突发奇想或许可以用这个前缀tire实现没库存的规格选择
思路
1、笛卡尔积,生成所有的sku
2、每一个sku的属性全排列插入字典树
防止出现”4G/红色”在前缀树中无法匹配的问题
全排列代码参考
3、如果当前选择规格属性值在前缀树中匹配了库存为0的sku,则把这个sku属性中没有选择的值在视图上标灰,不能再选择。
具体实现我暂时就不做了
具体实现:这个仓库,现在我不做,以后有时间可能就做了。
https://github.com/withwz/tire-spec-select
笛卡尔积代码
function cartesian(arr) {
if (arr.length < 2) return arr[0] || [];
return [].reduce.call(arr, function (col, set) {
let res = [];
col.forEach(c => {
set.forEach(s => {
let t = [].concat(Array.isArray(c) ? c : [c]);
t.push(s);
res.push(t);
})
});
return res;
});
}
const res = cartesian([[30,40,50,60], ["电动车", "电脑", "驾照"]])
console.log(res)
前缀树代码
class TrieNode {
constructor() {
this.numPass = 0;//有多少个单词经过这节点
this.numEnd = 0; //统计单词的个数
this.edges = [];
this.value = ""; //value为单个字符
this.isEnd = false;
}
}
/**
* 前缀树
* -----
* @see https://segmentfault.com/a/1190000013018855
*/
class Trie {
constructor() {
this.root = new TrieNode();
}
insert(word) {
var cur = this.root;
for (var i = 0; i < word.length; i++) {
var c = word.charCodeAt(i);
c -= 48; //减少“0”的charCode
var node = cur.edges[c];
if (node == null) {
var node = (cur.edges[c] = new TrieNode());
node.value = word.charAt(i);
node.numPass = 1; //有N个字符串经过它
} else {
node.numPass++;
}
cur = node;
}
cur.isEnd = true; //樯记有字符串到此节点已经结束
cur.numEnd++; //这个字符串重复次数
return true;
}
/**
* 先序遍历
* @param {function} cb
*/
preTraversal(cb) {
function preTraversalImpl(root, str, cb) {
cb(root, str);
for (let i = 0, n = root.edges.length; i < n; i++) {
let node = root.edges[i];
if (node) {
preTraversalImpl(node, str + node.value, cb);
}
}
}
preTraversalImpl(this.root, "", cb);
}
}
测试
var trie = new Trie();
trie.insert("I");
trie.insert("Love");
trie.insert("武昭");
trie.insert("武昭");
trie.insert("武昭在哪里???");
trie.insert("武昭在干什么???");
trie.insert("武昭🙂???");
trie.insert("武昭没吃饭???");
trie.insert("China");
trie.insert("China");
trie.insert("China");
trie.insert("China");
trie.insert("xiaoliang");
trie.insert("xiaoliang");
trie.insert("man");
trie.insert("handsome");
trie.insert("love");
trie.insert("Chinaha");
trie.insert("her");
trie.insert("know");
console.log("包含武(包括本身)前缀的单词及出现次数:");
console.log("---------------start--------------------")
var map = {}
trie.preTraversal(function (node, str) {
if (str.indexOf("武") === 0 && node.isEnd) {
map[str] = node.numEnd
}
})
for (var i in map) {
console.log(i + " 出现了" + map[i] + " 次")
}