阿里面试被问到用Vue手写一个功能,我懵了!
之前去阿里的二面,信心满满的我准备了一堆面试题,想着可以暴打面试官了,很是开心!结果去了以后,他喵的居然让我给他现场机试实现一个功能,当场蒙蔽了我!
具体功能如下 gif:
需求设计
差点凌乱,结果一想,这难吗? 难就难在没有思路。于是这时的我两腿一蹬,大脑开始高速运转,生成如下流程图:
这么看来好像就清晰很多了,果然设计是编程中不可或缺的一步!
正式 coding
首先我问面试官,后台响应回来的详情数据是什么结构,于是他给了我这么一坨
{ json1: [ ["红色", "黄色", "蓝色"], ["S", "M"], ["棉的", "涤纶"], ], json2: [ { color: "红色", type: "S", mianliao: "棉的", price: 100, }, { color: "红色", type: "M", mianliao: "棉的", price: 200, }, { color: "红色", type: "S", mianliao: "涤纶", price: 300, }, { color: "红色", type: "M", mianliao: "涤纶", price: 400, }, { color: "黄色", type: "S", mianliao: "棉的", price: 500, }, { color: "黄色", type: "M", mianliao: "棉的", price: 600, }, { color: "黄色", type: "S", mianliao: "涤纶", price: 700, }, { color: "黄色", type: "M", mianliao: "涤纶", price: 800, }, { color: "蓝色", type: "S", mianliao: "棉的", price: 900, }, { color: "蓝色", type: "M", mianliao: "棉的", price: 1000, }, { color: "蓝色", type: "S", mianliao: "涤纶", price: 1100, }, { color: "蓝色", type: "M", mianliao: "涤纶", price: 1200, }, ] }
我们从这个结构不难看出,json2 就是具体的数据,而 json1 里面存放是三个维度的分类,实现效果差不多是这样:
所以问题不大,我们先把 json1 的数据渲染出来再说。
<div v-for="(rowArr, index) in mockData.json1" :key="index"> <a v-for="(item, i) in rowArr" :key="i" @click="changeData(index,item)">{{item}}</a> </div>
上述数据我们保存在 mockData 中,只遍历 json1,效果出来了,适当加点样式:
#app a { text-decoration: none; border: 1px solid grey; margin: 8px; padding: 6px; display: inline-block; color: grey; } #app a.active { border: 1px solid red; color: red; }
出来了,beautiful:
逻辑处理及代码优化
面试官在告知我需求的时候,强调又强调数据不能写死,聪明的我当然明白,意思就是要尽可能让我们的前端代码有更高的复用性,说白了就是可能会匹配颜色、尺码、面料,也可能会用金额、风格来匹配。
设计一个万能属性匹配器
可以想象,不管他是什么属性,但只要是【条件对象】的 abc 属性,与【数据对象】的 abc 属性一致,我就可以认为筛选出来的就是这个对象,因此不要在乎 abc 这个名,岂不就通用性很高啦。接着我们在 data 下声明一个 condition 对象来存储当前选中的各项属性,再给他默认值。
先回顾一下数据结构:
data() { return { types: [], // 保存从 json2 中获取的动态属性名称 condition: {}, // 有 json1.length 个属性,分别是前三项 color、type、mianliao mockData: { json1: [ [ "红色", "黄色", "蓝色" ], [ "S", "M" ], [ "棉的", "涤纶" ], ], json2: [ { color: "红色", type: "S", mianliao: "棉的", price: 100, } /*....省略数据*/ ] } } }
模拟 created 中动态获取,并动态生成 types 和 condition
created(){ this.types = Object.keys(this.mockData.json2[0]); for (let i = 0; i < this.types.length; i ++) { // 由于分类有可能没有数据的属性多,所以判断一下 if (!this.mockData.json1[i])return; let propName = this.types[i]; this.$set(this.condition,propName,this.mockData.json1[i][0]); } },
注意注意:
- 第 2 行是讲具体商品数据中的所有属性名存储到数组中;
- 第 7 行则是动态添加响应式属性,这是 Vue2 中动态添加属性必须要做的,否则更改数据页面那个属性不变化,Vue3 这个问题已经解决。
点中后的激活效果
<a :class="{ active: condition[types[index]] === item }" href="#" v-for="(item, i) in rowArr" :key="i" >{{ item }}</a>
这个比较简单!
核心代码(过滤数据)
1、首先我们给 a 标签添加点击事件,点了那项,就更改其中颜色或者尺码或者面料的值,因此相同函数我们必须要知道点了哪个类别,这里我们可以用【外层的 index】做区分,给 a 标签加上事件:
<a @click="changeData(types[index], item)" a>{{item}}</a>
2、保存这个数据变化
changeData(prop, data) { let self = this; self.condition[prop] = data; }
3、有了数据,就可以做过滤显示了,computed 是最佳人选
computed: { showGoodsInfo() { return his.mockData.json2.filter((e) => { return diffObjectByKeys(this.condition, e); }); }, }
4、核心的工具函数,对比两个对象的函数还没实现,我们去实现它,这个函数接收俩对象,对比其属性值,全都相同,返回 true,否则 false。
function diffObjectByKeys(obj1, obj2) { let isEqual = true; for (let key in obj1) { let v = obj1[key]; if (obj2[key] && obj2[key] === v) { continue; } else return false; } return isEqual; }
5、别忘了使用这个计算属性:
价格是: {{ showGoodsInfo }}
最终效果
至此,完美实现,非常 Nice!
码云笔记 » 阿里面试被问到用Vue手写一个功能,我懵了!