实现SKU功能
2022/6/30 4:19:35
本文主要是介绍实现SKU功能,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
实现效果
TODO
- 获取服务端数据,分析数据结构
- 构建 sku 组件,搭建基础框架
- 编写页面交互逻辑代码
分析页面入口传递何种数据
- 从主页面跳转到详情页面的 url :v1/spu/id/{{id}/detail
- 所以跳转详情页面需求传递当前 spu 的 id,跳转到详情页面后向服务器获取当前 spu 数据填充到页面
- 从服务器获取到的数据格式如下:
分析数据结构
-
总体结构猜测
-
重点结构(sku_list)
-
sku_list 是一个数组类型的数据,里面包含的是一个个对象,每个对象都是一个 sku
搭建容器框架
- 组件是数据的载体,既然我们了解了数据结构那我们就根据数据结构来搭建框架
- 我将 sku 作为一个组件封装起来,组件需要从外部传递 sku_list 以及 默认 sku_id 给组件调用
<m-sku-list list="{{sku_list}}" defaultSkuId="{{default_sku_id}}"></m-sku-list>
-
我们已经有了数据,分析一下页面结构
-
如下图:我们需要一个容器承接 sku详情数据,另个容器承接 sku 规格数据
-
详情数据好说,都是现成直接往里填充就好,但是规格就没有现成的可以使用了,因此我们需通过分析规格数据格式抽象一个 用于一定规格的对象来帮助我们搭建容器
// 抽象规格数据 // 如上图,一共有三种分类(颜色、款式、尺码),三种分类各自组合成一个sku,这样多个数据的情况下适用数组管理 // 每种规格都被视作一个对象,对象包含 标题、分类id、组合合成的规格 component({ data:{ specsList:[] // 规格列表用于搭建框架 } })
- 为了得的上述的数据结构,我们需要对外部传递给我们的数据进行二次封装
component({ ..., observers:{ "list":function(list){ // 防空 if (list.length === 0) return // 搭建 spu 规格模板 const specList = list[0].specs.map(item => { return { keyId:item.key_id, key:item.key, category:[] } }) // 填充 sku 规格模板 specList.map(m => { // 获取各个规格 list.map(i => { // 获取规则中一种分类对应的所有样式,例如:颜色:红、白、蓝 const category = i.specs.find(spec => { return m.keyId === spec['key_id'] }) // 防止重复保存相同的样式 if(m.category.length === 0) { m.category.push(category) } else { const b = m.category.find(c => c["value_id"] === category['value_id']) if(!b) m.category.push(category) } }) }) } } })
- 好了,完成到这里我们就可以轻松有空的搭建好容器框架了,我们的 todo-list 也完成 70%,剩下的 30% 也是最难的了…
编写页面交互逻辑
-
交互逻辑有很多,在显示之前我先将其一一列出来,以防后思维混乱
- sku 规格选择,三种分类组成一种规格(一般):
- 实现选中与取消选中
- 同一分类不能个被选中,例如:颜色不能同时选中为红色之后有加选白色
- 同一分类点选未选中的样式,需要将当前样式取消,例如:当前红色为选中状态,点选白色后,选中白色取消红色
- 规格可选后,我们对选中样式进行约束(最难)
- 当未选中任何样式时,所有样式都是可选状态
- 当选中样式仅有一个时,要开放同类样式,同时做逻辑判断哪些样式不可选,例如:我仅选了红色,那么颜色分类的其他选项对我来说是可选状态,而其他分类就不一定是可选状态
- 当选中样式已满时,其他样式都不可选
- 其他状态,直接做逻辑判断是否可选
- 到这里已经实现了对 sku 的约束,最后是 sku 详情的绑定
- 当样式选满,自动切换到与当前 sku 匹配的详情(简简单单)
- sku 规格选择,三种分类组成一种规格(一般):
-
分析选中与取消选中
- 第一个想法就是通过 active 与 disable 两个样式来控制可选与不可选,那么问题来了,这么动态添加这两个样式呢???
- 理所当然是通过点击事件,那么我们点击就给他上 active???,那点了同类其他样式,我要怎么取消 active ???
- 最终,我使用数组来管理选中状态,分析一下吧,根据上述例子,最多能存在三个分类同时被选中,那么我们的selectedList 列表中最多就存在3个选中状态,
- 当我们点选一个状态时,先判断这个状态是否已经被选中,若选中则将其取消选中
- 未选中,有两种结果
- 我点的样式已选中,需要替换原选中样式
- 该分类样式未被选中,直接选中
- 根据上限分析,我们来编写代码
component({ data:{ ..., // 根据上述分析,我们需要一个数组来管理选中状态 selectedList:[] }, ... methods:{ // 点击触发切换样式 selectedSku(e) { // 切换样式,我们也需要知道,我们当前点击的是哪个样式(category),disable是禁选 const {category,disable} = e.currentTarget.dataset if (disable) return // 获取当前选中样式的列表 const arr = this.data.currentSelect // 判断是否点选已选中的样式 // 获取当前选中的样式分类 const index = arr.findIndex((item,index) => { return item['key_id'] === sku['key_id'] }) // 简单逻辑判断 if (index === -1) { // 列表中没有该分类 arr.push(sku) }else { // 列表中已有该分类,那就是取消选中或,更换选中 if (sku['value_id'] === arr[index]['value_id']) { arr.splice(index,1) }else { arr.splice(index,1,sku) } } this.setData({ currentSelect:arr }) }, } })
- 分析样式约束
- 这真令人头痛啊!!!,累了毁灭吧!!!
- 回到正题,实现样式约束,核心是将当前选中的样式与 sku 组合的比较,当前选中的样式好说,我们完成上一步就已经获得了,sku组合就相对麻烦,因为他藏的很深啊,又是数组又是对象,对象里面还有数组,数组里面还有对象,你膈这套娃呢???
- 话不多说,我们先重新组织一下 sku 的格式,以便我们调用
- 解释一下,我已 key_id 为键 ,key 为其值,value 同理,顺便保存了 该 sku 的 id,以便在 sku 详情中获取原列表数据
- 好了准备工作完成,那就开始分析约束条件(从简单的开始吧)
- 当未选中任何状态,那我们就不应该约束任何样式
- 当已选中最大可选状态,那其他样式均被禁用
- 当有且只有1个状态被选中,该分类的样式均可选,其他分类需要逻辑判断
- 其他状态,直接逻辑判断
- 分析完毕上代码吧
<view class=" category-item <!-- 默认样式 --> {{m.selected(item['key_id'],item['value_id'],currentSelect) ? 'active' : ''}} <!-- 选中样式 --> {{m.isDisable(currentSelect,item,allSku,maxSelectSize) ? 'disable':''}}" <!-- 禁用样式 --> data-category="{{item}}" <!-- 当前 item 携带的样式信息 --> data-disable="{{m.isDisable(currentSelect,item,allSku,maxSelectSize)}}" <!-- 判断 item 是否已禁用 --> bind:tap="selectedSku"> <!-- 点击触发选中 --> <view class="category-item-inner">{{item.value}}</view> </view> <wxs module="m"> ... var isDisable = function (currentSelect,item,allSku,maxSize) { var flag = true // 当前选项长度是 0 if (currentSelect.length === 0) { flag = false } else if (currentSelect.length === maxSize) { // 当前选项长度是最大选项值时,item 若非选中则禁用 currentSelect.forEach(function (c){ // console.log("wx",c['key_id'] === item['key_id']) if (c['key_id'] === item['key_id']){ if (c['value_id'] === item['value_id']) { flag = false } } }) } else if (currentSelect.length === 1) { // 当前选项长度是只有 1 个时 // 相同类型可选 if (currentSelect[0]['key_id'] === item['key_id']){ flag = false return } // 非相同类型需要判断 allSku.filter(function (s) { var cv = currentSelect[0]['value_id'].toString() // console.log(s[cv] , currentSelect[0]['value']) return s[cv] === currentSelect[0]['value'] }).forEach(function (s) { var v = item['value_id'].toString() if (s[v] === item['value']) { flag = false } }) } else { // 当前选项长度大于 1 小于 最大选项值时 // 先从所有 sku 中过滤出符合当前选中的 sku var filterSku = [] currentSelect.forEach(function (cs) { filterSku = allSku.filter(function (s) { var cv = cs['value_id'].toString() // console.log(s[cv] , currentSelect[0]['value']) return s[cv] === cs['value'] }) }) // 当 item 与 选中列表中的样式组合 能在 sku 列表中找到 filterSku.forEach(function (fs) { var v = item['value_id'].toString() if (fs[v] === item['value']) { flag = false } }) } return flag } module.exports = { ..., isDisable:isDisable, } </wxs>
- sku 详情的绑定
- 能走到这里,这 sku 详情绑定就是洒洒水啦
- 上面定义一个 currentSelect 管理当前选中状态,当选项满最大可选值时,触发重新设置当前状态
component({ ..., observers: { ..., "currentSelect":function (currentSelect) { if (currentSelect.length === this.data.maxSelectSize) { // 获取数据 const {allSku} = this.data const {list} = this.properties // 筛选sku let filter = allSku currentSelect.map(cs =>{ filter = filter.filter(f => { return f[cs['value_id'].toString()] === cs['value'] }) }) // 未筛选中,返回 if (filter.length === 0) return // 筛选中 const sku = list.find(item => { return item.id === filter[0].id }) this.setData({ currentSku:sku }) } } } })
这篇关于实现SKU功能的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-03-29Gitlab 实现仓库完全迁移,包括所有提交记录、分支、标签
- 2024-03-28numpy moving average
- 2024-03-28lsp框架
- 2024-03-28in文件
- 2024-03-28ninoka nk 700
- 2024-03-28volatile java
- 2024-03-28netflix hystrix
- 2024-03-28landsat ndvi
- 2024-03-28变分法
- 2024-03-28FMZ股票实盘、模拟盘程序化交易实战--股票版DualThrust策略