面试被问到用Vue手写一个功能,直接懵了

46,033 阅读3分钟

东窗事发

之前去阿里的二面,信心满满的我准备了一堆面试题,想着可以暴打面试官了,很是开心!结果去了以后,他喵的居然让我给他现场机试实现一个功能,当场蒙蔽了我!

具体功能如下gif:

 

需求设计

差点凌乱,结果一想,这难吗? 难就难在没有思路。于是这时的我两腿一蹬,大脑开始高速运转,生成如下流程图:

 

这么看来好像就清晰很多了,果然设计是编程中不可或缺的一步!

正式coding

首先我问面试官,后台响应回来的详情数据是什么结构,于是他给了我这么一坨

{
        json1: [
          ["红色", "黄色", "蓝色"],
          ["S", "M"],
          ["棉的", "涤纶"],
        ],
        json2: [
          {
            color"红色",
            type"S",
            mianliao"棉的",
            price100,
          },
          {
            color"红色",
            type"M",
            mianliao"棉的",
            price200,
          },
          {
            color"红色",
            type"S",
            mianliao"涤纶",
            price300,
          },
          {
            color"红色",
            type"M",
            mianliao"涤纶",
            price400,
          },
          {
            color"黄色",
            type"S",
            mianliao"棉的",
            price500,
          },
          {
            color"黄色",
            type"M",
            mianliao"棉的",
            price600,
          },
          {
            color"黄色",
            type"S",
            mianliao"涤纶",
            price700,
          },
          {
            color"黄色",
            type"M",
            mianliao"涤纶",
            price800,
          },
          {
            color"蓝色",
            type"S",
            mianliao"棉的",
            price900,
          },
          {
            color"蓝色",
            type"M",
            mianliao"棉的",
            price1000,
          },
          {
            color"蓝色",
            type"S",
            mianliao"涤纶",
            price1100,
          },
          {
            color"蓝色",
            type"M",
            mianliao"涤纶",
            price1200,
          },
        ]
}

我们从这个结构不难看出,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;
  border1px solid grey;
  margin8px;
  padding6px;
  display: inline-block;
  color: grey;
}
#app a.active {
  border1px 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]);
    }
  },
  • 注意注意
  1. 第2行是讲具体商品数据中的所有属性名存储到数组中
  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>
  1. 保存这个数据变化
 changeData(prop, data) {
      let self = this;
      self.condition[prop] = data;
 }
  1. 有了数据,就可以做过滤显示了,computed是最佳人选
 computed: {
    showGoodsInfo() {
      return his.mockData.json2.filter((e) => {
        return diffObjectByKeys(this.condition, e);
      });
    },
  }
  1. 核心的工具函数,对比两个对象的函数还没实现,我们去实现它,这个函数接收俩对象,对比其属性值,全都相同,返回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;
}
  1. 别忘了使用这个计算属性:
价格是: {{ showGoodsInfo }}

最终效果

非常的Nice!!