我在 Vue 2 时代就在使用 element-ui,到了 Vue 3 时代我将它的官方 Vue 3 版本 element-plus 作为我的首选 UI 库。
我曾发布 tailwind-extensions 和
unocss-preset-element-plus 两个包,方便将 element-plus 和 tailwindcss、unocss 结合起来使用。我还给 element-plus 提过两个 PR #12549 和 #14062,提高了 FormRules 类型质量。
element-plus 一直都是我快速开发的好伙伴。但最近面对各种业务或奇葩或实际的需求,我发现 element-plus 有些地方不能很好地满足我的需要。
基于我个人代码审美主观来说,我认为 element-plus 某些 API 设计不够统一,给我带来了割裂感。
如果我有以下一组数据,每个元素中的 name 作为文本显示,而 value 作为值被实际使用。
const data = [ { name: 'A', value: 1 }, { name: 'B', value: 2 }, { name: 'C', value: 3 },];
如果我需要多选,我可以使用 el-checkbox,下面就是一个例子。
<script setup lang="ts">import { ref } from 'vue';import { ElCheckboxGroup, ElCheckbox } from 'element-plus';const data = [ { name: 'A', value: 1 }, { name: 'B', value: 2 }, { name: 'C', value: 3 },];const value = ref<number[]>([]);</script><template> <el-checkbox-group v-model="value"> <el-checkbox v-for="item of data" :key="item.value" :label="item.value" > {{ item.name }} </el-checkbox> </el-checkbox-group></template>
这个例子很简单,但是却反映了 1 个不算大但也不算小的问题:label 会被用来作为值,但 label 这个单词本身并没有值的含义,这给我造成了认知混乱。
如果我需要单选,我可以使用 el-radio,下面就是一个例子。
<script setup lang="ts">import { ref } from 'vue';import { ElRadioGroup, ElRadio } from 'element-plus';const data = [ { name: 'A', value: 1 }, { name: 'B', value: 2 }, { name: 'C', value: 3 },];const value = ref<number>();</script><template> <el-radio-group v-model="value"> <el-radio v-for="item of data" :key="item.value" :label="item.value" > {{ item.name }} </el-radio> </el-radio-group></template>
和 el-checkbox 类似,label 也被用来作为值,这同样给我造成了认知混乱。
在选项数量较多时,我可以使用 el-select 来做单选或者多选,下面是一个单选的例子,多选也相差不大。
<script setup lang="ts">import { ref } from 'vue';import { ElSelect, ElOption } from 'element-plus';const data = [ { name: 'A', value: 1 }, { name: 'B', value: 2 }, { name: 'C', value: 3 },];const value = ref<number>();</script><template> <el-select v-model="value"> <el-option v-for="item of data" :key="item.value" :label="item.name" :value="item.value" ></el-option> </el-select></template>
和上面两个例子不同,label 作为文本,value 作为值,我认为这清晰明确得多。如果都采取 el-select 的 API 设计,对于我来说真的太好了。
我翻查过 element-ui 的文档,发现 element-plus API 设计大部分都跟随前者的 API 设计,我不太确定这里面是否带有历史包袱的因素。
主观来说,我认为 element-plus 功能支持可以做得更好。
我曾经接到过一个实际的业务需求,有大概一百多条数据,需要支持多选,多选时需要默认隐藏大部分数据,还需要支持全选、全不选和反选。很自然地,我使用了 el-select,因为 el-select 提供了现成的多选和多选时隐藏大部分数据这两项的支持。
遗憾的是,在支持全选、全不选和反选时我却陷入了僵局:el-select 并没有提供相应的插槽,我没有办法在不修改源码的情况下优雅地将这些操作收纳到 el-select 的下拉菜单中。
最后,我只能将这些操作放到了 el-select 外部的下方,被评价“不好看但能用”
<script setup lang="ts">import { ref } from 'vue';import { ElSelect, ElOption, ElButton } from 'element-plus';const data = Array.from({ length: 100 }).map((_, index) => ({ value: index, label: index,}));const value = ref<number>();</script><template> <el-row> <el-col> <el-select v-model="value" multiple filterable collapse-tags collapse-tags-tooltip > <el-option v-for="item of data" :key="item.value" :label="item.name" :value="item.value" ></el-option> <!-- 我想要的 --> <!-- <template #action> <el-space> <el-button text>全选</el-button> <el-button text>全不选</el-button> <el-button text>反选</el-button> </el-space> </template> --> </el-select> </el-col> <el-col> <!-- 实际做出来的 --> <el-space> <el-button text>全选</el-button> <el-button text>全不选</el-button> <el-button text>反选</el-button> </el-space> </el-col> </el-row></template>
如果 el-select 支持 Action Slot 该多好啊!那样我就可以轻轻松松地完成需求了,而且页面也优雅、好看一些。我曾经翻查过 naive-ui 和 ant-design-vue,发现它们都支持这类场景,这让我更希望 el-select 能够增加这个功能了。
但是,添加这个功能支持需要花费大量时间。首先需要创建 Discussion 征询大家的意见,之后需要自己创建 PR 或者等待其他人来实现它。如果创建了 PR,可能需要一两个月的 Code Review,因为 element-plus 的维护者们真的太忙了。PR 合并后,还需要等待正式发版。
简而言之,我认为 element-plus 很棒,但是某些 API 设计不够统一,给我带来了割裂感,功能支持有所欠缺,可以做得更好。在需要快速开发业务需求的场景下,这两方面的缺点被放大了不少,我的前端开发工作进度会因此有所卡顿。
客观来说,要改进这两方面问题并非一朝一夕之事。遗憾的是我没有太多时间参与改进或是等待改进,我现在在尝试 naive-ui 和 ant-design-vue,它们给我的感觉都还不错。衷心希望 element-plus 越来越好,也感谢 element-plus 陪我走过几年前端时光
原文
链接:
https://juejin.cn/post/7281462577116299319