4

Ant Design Vue

 2 years ago
source link: https://zhuanlan.zhihu.com/p/423456742
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Ant Design Vue 3.0 的那些正经事儿

Ant Design Vue

说在前面,这不仅是一篇 3.0 的功能介绍,更是阐述背后变更的原因,以及设计的逻辑,如果你正在开发自己的组件库,期望能够帮助到您 。 ​

没错,3.0 她来了,3.0 是一个吉利的数字,她比2大1,但又比4小1,就是那么神奇,不是嘛!(⊙o⊙)… ​

v2 版本似乎发布了没有多久,为什么直接调到了 v3,主要原因是: ​

  • 她有较多的更新,同时有一些是无法向下兼容的,例如,使用 dayjs 替换 momentjs
  • v2 版本主要是我们为了兼容 Vue 3 开发的一个版本,他没有太多的新特性,少数的破坏性更新也只是为了更好的兼容 Vue 3 的,对于一些新的功能和交互只能推迟到 v3 版本来实现了。
  • 3 真的是一个吉利的数字,他刚好和 vue 3 一致,不会让一些人误解,未来的 4 5 6......,也只会出现“我都使用 4 了,你们还在用3” 的说法,不得不说,这的确可以减少一些答疑成本(太机智了)
  • 团队开始全职维护该组件库,节奏会比以往要快很多,前方加速,请系好安全带(更新快了,你说我不稳定,更新慢了,你说我不维护,太 TM 难了)

说回正经事儿

3.0 都更新了啥?我想从源码层面、功能层面、易用性层面、性能层面分别讲解。 ​

源码层面

使用 TS + Composition Api 进行重构,目前只有极个别的组件还在使用 Option Api,我们会逐步重构,但这些组件不会有破环性更新,所以不用担心未来的升级成本。搭配 Volar 你会得到更好的类型提示。不得不说 Vue 3 在 TS 方面有了很大的提升,但依然还有一些不足,对组件库来说体感较强的是 Vue 3 源码类型复杂度较高,泛型组件不友好,组件属性类型复用不友好,这三个问题分开来看都有一些方案去解决,但三者结合起来,我们依然没有找到一个非常好的平衡点去规范它,当然,我们在 TS 方面也并不深入,如果你比较擅长,也非常欢迎加入我们,一起为 Vue 3 生态,为开源贡献一份自己的力量。 ​

目前我们对于组件属性的类型定义方案是把 props 单独抽出来定义成一个函数,举个例子:

import type { ExtractPropTypes, PropType } from 'vue';

export type ButtonTypes = 'primary' | 'ghost' | 'dashed' | 'link' | 'text';

export const buttonProps = () => ({
 type: { type: String as PropType<ButtonTypes> }
})

export type ButtonProps = Partial<ExtractPropTypes<ReturnType<typeof buttonProps>>>;
                                                              
export default defineComponent({
 name: 'AButton',
 props: buttonProps(),
})

通过这种方式,我们同时导出 buttonProps ButtonProps , 前者一般是给其他组件或用户二次封装组件使用,后者一般是用户写业务代码使用,至于前者为何是函数返回,这里涉及到一个引用类型默认值的问题,就是那个Vue 2 时代经典的面试题,为何定义 data 要用函数返回是一样的道理。通过这种方式算是达到了类型复用的目的。如果你有更好的建议,欢迎通过 PR 的方式讨论,你可以从一个简单的组件开始。 ​

功能层面

简单一句话就是,同步了 antd 4.x 的功能:

1、自定义时间库,使用 dayjs 作为默认时间库,提供 momentjs、date-fns 快速切换功能

2、Tree、TreeSelect 支持虚拟滚动,Table 支持表格合计

3、更好的暗黑主题

4、更好的无障碍辅助

5、支持 RTL,除了少量未重构组件尚不支持,正式版之前添加

6、CSS Variables 正式版之前添加 ​

更多细节功能不再展开叙述。

易用性层面

antd 经历了默认好看,到现在一直在追求的默认好用,但好用包含了功能强大、API 简单,这两个本身就是矛盾的存在,应该说我们一直探索的是他们之间的平衡点,如何在扩展更多功能的时候,保持 API 的简单易用。 ​

本次主要更改了 TreeTreeSelectTableCard 的自定义渲染时的API,我们以Table举例,

<template>
  <a-table :dataSource="dataSource" :columns="columns" />
</template>
<script>
  export default {
    setup() {
      return {
        dataSource: [
          {
            key: '1',
            name: '王二蛋',
          },
        ],

        columns: [
          {
            title: '姓名',
            dataIndex: 'name',
          },
        ],
      };
    },
  };
</script>

渲染结果如下:

很简单,对不对,但王二蛋是一位坐拥亿万资产的富二代,也是我们的VIP客户,老板期望对该类客户进行特别标示,名字要加粗加红加V加...,怎么玩,在 React 里面,我们可以直接: ​

name: <div class="jia_cu jia_hong jia_v">王二蛋</div>

当然在 Vue 中,你依然可以使用同样的方式进行配置,前提是使用 vue-jsx 语法或手写 render 函数,但 template 语法会让我们得到更好的性能,比 react 还要好的性能。那么在 template 中怎么配置,在 1.x 和 2.x 版本中我们约定了一个规则是在 columns 中通过 slots 指定一个"任意"名称的插槽进行配置:

<template>
  <a-table :dataSource="dataSource" :columns="columns">
   <template v-slot:customName="{record, text}">
     <template v-if="record.name === '王二蛋'">
       <div class="jia_cu jia_hong jia_v">王二蛋</div>
      </template>
      <template v-else>{{text}}</template>
    </template>
  </a-table>
</template>
<script>
  export default {
    setup() {
      return {
        dataSource: [
          {
            key: '1',
            name: '王二蛋',
          },
        ],

        columns: [
          {
            title: '姓名',
            dataIndex: 'name',
            slots: { customRender: 'customName' // 名称任取}
          },
        ],
      };
    },
  };
</script>

似乎看着没有什么问题,的确这种方式陪伴了我们好多年,似乎大家也都已经习惯了这种配置方式,但是在权衡了很久之后,我们依然决定打破这个舒适圈,这种方式的 API,他有两个弊端: ​

1、配置膨胀,如果你的每一列都需要自定义渲染,你需要在 columns 中都要配置上 slots,也要相应的在 template 提供对应的插槽。 ​

2、才是最主要的问题,他有一个很大的风险就是,我们无法限制用户自定义的插槽名称,那么如果未来组件内部需要扩展插槽,就会有冲突的风险,这是一个不可控的风险。 ​

先插一句,防杠精,其实我们是提供了 a-table-column 方式去构建配置的,这种方式并不需要去配置插槽,但我们并没有主推这种方式,

原因一是个人感觉 columns 要比 a-table-column 少写很多字符,也更直观些;

原因二是 columns 的形式,相较于 a-table-column 性能略高,其实 a-table-column 内部依然会转化为 columns,转化的过程目前有两种方式,第一种是父组件 table,遍历子组件 a-table-column,生成 columns;第二种是子组件 onMounted 之后,将子组件信息告诉父组件,这里还有个恶心的点是,构建子组件在父组件的位置索引,Vue 是不承诺渲染"过程顺序"的,只保证"结果顺序",这个索引的构建方法我就不展开了;除此之外,上述两种方法其实都用了非Vue文档API,都是有一定的风险的。

总之,因为大部分用户选择了 columns,我们期望将 columns 的使用难度降低,让table更加易用。 ​

所以 3.0,我们废弃了 column.slots 的配置,而是提供了统一的自定义出口 v-slot:bodyCell,使用新的 API 优化后的代码如下:

<template>
  <a-table :dataSource="dataSource" :columns="columns">
  	<template v-slot:bodyCell="{record}">
    	<template v-if="record.name === '王二蛋'">
      	<div class="jia_cu jia_hong jia_v">王二蛋</div>
      </template>
		</template>
  </a-table>
</template>
<script>
  export default {
    setup() {
      return {
        dataSource: [
          {
            key: '1',
            name: '王二蛋',
          },
        ],

        columns: [
          {
            title: '姓名',
            dataIndex: 'name',
          },
        ],
      };
    },
  };
</script>

插槽中可以不需要 v-else,组件内部会自动 fallback 到默认值(王二蛋) ,正如我前文所说,当我们新增插槽的时候,会有和你自定义插槽冲突的风险,希望你没有起名叫 bodyCell 的插槽,除此之外,headerCell``customFilterDropdown``customFilterIcon都是新增的插槽,我想应该大概可能不会那么巧就碰上了吧。 ​

同样的逻辑,我们优化了 Tree、TreeSelect 自定义 title 的逻辑,不再需要在 treeData 数据源中通过 slots 配置自定义插槽,而是由 v-slot:title 统一接管。Card 自定义tab,不再需要在 tabList 数据源中通过 slots 配置自定义插槽,而是通过 v-slot:customTab接管。

性能层面

1、FormItem 使用 provide/inject 代替 cloneElement,减少 render 次数,提升表单性能

2、废弃 TreeNode、TreeSelectNode 使用 treeData 属性替代

3、在 2.x 版本中,Select、AutoComplete 支持了虚拟滚动,在 3.0 中,我们又新增了 Tree、TreeSelect 组件支持虚拟滚动。可以轻松应对大数据渲染。

为什么 Table 还不支持虚拟滚动?

两个原因:破坏性更新 和 成本 问题

如果要支持完善的虚拟滚动,会有很大的成本,注意,这里说的是完善的虚拟滚动,不是简单一个列表,我们要支持固定列、行列合并、展开、子表格等等一系列问题,开发成本完全不亚于一套组件库了,这也是为什么 MUI(原名 material ui 7万+ star 的开源项目) 专门招聘了全职人员维护虚拟表格组件。

虽然你在 antd react 版本文档中有一个虚拟滚动的示例,但那完全是借助第三方组件自定义的一个简单虚拟滚动示例,如果要添加固定列、选择、拖拽、展开等功能,成本非常高(几乎不可用),你可以尝试在 react 版本的 issue 下搜索 table 虚拟关键词查看相关问题。

对于Table,我们也会推出独立的产品去解决大数据展示问题,初版应该不会让大家等太久,如果顺利,最近一两个月会和大家见面,敬请期待! 可以关注下官方公众号(搜索 ant-design-vue),我们会及时通过公众号发布通知。

4、其它很多用户无感知的组件内部性能优化 ​

升级指南查看:

这部分展开来说,有很多干货,我也会在 10.23 早早聊Vue专场会议(免费的,尤大也来)上分享给大家,大家可以关注下,关注公众号后回复 ”大会“,查看会议详情


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK