跟随Element学习Vue小技巧(14)——Cascader

2,960 阅读2分钟

如果结果不如你所愿

就在尘埃落定前奋力一搏

前言

从前有座山
山里有座庙
庙里有个老和尚
老和尚给小和尚讲故事:
从前有座山... 你听过最长的故事是什么呢?

  • 一千零一夜
  • 哆啦A梦
  • 名侦探柯南

我想,所有的故事加起来,都没有你自己的故事长,只要你怀有希望,故事就不会那么容易结局!
准备好了吗?一起写属于我们的故事 ^_^

1 Cascader

递归

3.14159265358979323846264
π至今都无法穷尽,级联选择也是无穷无尽的吗?
我想是吧,只要容量足够大!!!
那么,一级又一级是如何做到的呢?
递归呗
我之前也是这样想的

代码片段

<el-cascader-panel
  ref="panel"
  v-show="!filtering"
  v-model="checkedValue"
  :options="options"
  :props="config"
  :border="false"
  :render-label="$scopedSlots.default"
  @expand-change="handleExpandChange"
  @close="toggleDropDownVisible(false)">
</el-cascader-panel>
<template>
  <div
    :class="[
      'el-cascader-panel',
      border && 'is-bordered'
    ]"
    @keydown="handleKeyDown">
    <cascader-menu
      ref="menu"
      v-for="(menu, index) in menus"
      :index="index"
      :key="index"
      :nodes="menu"></cascader-menu>
  </div>
</template>

技巧解析

没想到吧,嵌套for循环,实现级联
menus=[Lv1List, Lv2List, ...]
外层放一个div.menu,内层ul>li
展开下一层,menus.push(Lv3List)
以此类推...
最终得到(.menu>ul>li*3)*3

最后送一个扁平化工具给你

const flatNodes = (data, leafOnly) => {
  return data.reduce((res, node) => {
    if (node.isLeaf) {
      res.push(node);
    } else {
      !leafOnly && res.push(node);
      res = res.concat(flatNodes(node.children, leafOnly));
    }
    return res;
  }, []);
};

说到底,还是递归嘛 JS中的递归 传送门

解构赋值

还记得那对吃货情侣吗?
走,吃火锅去
吃火锅

默契,是经过多少次的磨合,才能读懂你的每一个动作,每一个眼神

代码片段

render(h) {
  const { isEmpty, menuId } = this;
  ...
}
const { list=[] } = data;
const { keys: KeyCode } = AriaUtils;

技巧解析

直接赋值,menuId = this.menuId
解构赋值,
const {menuId} = menuId
解构赋值,默认值
const {menuId=''} = menuId
解构赋值,别名
const {menuId=code} = menuId

解构赋值 传送门

2 CascaderMenu

JSX语法

免对兔说:下回拉屎能不能擦干净点
回对口说:亲爱的,我怀孕了
JSX对JS说:买了把剪刀,一下子就美哒哒

代码片段

// Row
render(h) {
  return h(this.tag, {
    class: [
      'el-row',
      this.justify !== 'start' ? `is-justify-${this.justify}` : '',
      this.align !== 'top' ? `is-align-${this.align}` : '',
      { 'el-row--flex'this.type === 'flex' }
    ],
    style: this.style
  }, this.$slots.default);
}
// CascaderMenu
render(h) {
  const { isEmpty, menuId } = this;
  const events = { nativeOn: {} };

  // optimize hover to expand experience (#8010)
  if (this.panel.isHoverMenu) {
    events.nativeOn.mousemove = this.handleMouseMove;
    // events.nativeOn.mouseleave = this.clearHoverZone;
  }
  return (
    <el-scrollbar
      tag="ul"
      role="menu"
      id={ menuId }
      class="el-cascader-menu"
      wrap-class="el-cascader-menu__wrap"
      view-class={{
        'el-cascader-menu__list': true,
        'is-empty': isEmpty
      }}
      { ...events }>
      { isEmpty ? this.renderEmptyText(h) : this.renderNodeList(h) }
    </el-scrollbar>
  );
}

技巧解析

买把剪刀,果然帅气多了
常量绑定,双引号 tag="ul"
变量绑定,大括号 id={ menuId }
集体属性,解构, { ...events }
事件绑定,nativeOn={}
条件指令,isEmpty ? a : b
循环指令,for...in

jsx全面指南 传送门
用jsx写vue组件 传送门

参考链接

往期回顾