
1. 被几百条下拉选项逼疯之后我重新认识了filterable和clearable前阵子做后台管理系统遇到一个很现实的痛点工单分配页面里的所属项目下拉框数据是从接口拉的少说也有七八百条。用户每次点开选择器都要从头滚到尾找一圈下来少说十几秒。有人直接放弃在这页操作跑到群里问我这个项目ID你知道是多少吗我直接在数据库里改行不行当时我就意识到el-select这种组件文档里一行带过的属性放到真实业务里可能是好用和难用的分水岭。我后来给所有长列表下拉框统一加上了filterable可输入筛选和clearable可清空两个属性用户反馈直接反转选项目变成输入俩字回车就完事选错了点旁边的 x 一键清空重选再也没人抱怨找不到选项。这篇文章我就把这两个属性在真实项目里的用法、原理、组合姿势、踩坑记录都整理一遍尤其是远程搜索、表单校验、数据回显这些容易出问题的场景。适合正在用 Element-ui 做后台系统的同学参考也适合那些明明加了 filterable 但感觉还是卡卡的、怪怪的的朋友对照排查。1.1 没有 filterable 之前选一个选项有多痛苦先说一个真实场景。我们的组织架构里部门节点是按树形结构存的单选下拉要展示的是所有子部门汇总后的列表大概一千条左右。第一次做这个页面的时候我天真地以为用户慢慢找总能找到结果上线第二天就收到了五条反馈集中在同一句话这个下拉太长了找个部门眼睛都花了。更麻烦的是部门名称还有相似项比如华东供应链中心和华东供应链管理中心就差几个字用户滚动浏览时非常容易点错。点错之后呢没有 clearable 的话用户只能重新打开下拉再从一千条里找到刚才选错的项然后改成对的。这体验别提多糟了。有同事给了一个临时方案把下拉换成级联选择器按部门树一层层选。但产品同学并不接受因为用户有时候只记得部门名称的一个关键词比如供应链他不想一层层点进去找他希望在输入框里直接打字能筛出所有名称里带供应链的部门。这个诉求翻译成 Element-ui 的能力就是filterable。1.2 filterable 和 clearable 的基础用法filterable和clearable是 el-select 上的两个布尔 prop用法非常简单template el-select v-modelselectedProjectId filterable clearable placeholder请选择项目 el-option v-foritem in projectList :keyitem.id :labelitem.name :valueitem.id / /el-select /templatefilterable的含义是选择器允许用户直接在输入框里打字Element-ui 会根据输入的文本对下拉选项做一次包含匹配然后实时更新下拉列表。clearable的含义是当选择器里有选中值时鼠标悬停在组件上会显示一个 x 图标点击之后一键清空当前选中项。两个属性同时使用的时候交互上是这么分工的用户聚焦下拉 - 输入文字 - 列表实时过滤 - 键盘上下选择 - 回车确认 - 鼠标悬停 - 点击 x 清空。这套链路覆盖了查找、选择、改选三个动作比纯粹的滚动 点击高效太多了。我当时在页面上加这两行代码前后不超过五分钟但实际效果是工单分配这个页面的操作耗时从平均四十多秒降到了十几秒。别小看两个布尔属性它们在真实业务里就是一根救命稻草。1.3 组合使用时不可忽略的交互细节很多新手以为filterable就是能打字实际上它把 el-select 的交互模型从纯选择变成了选择 输入的组合框。这里有几个交互细节值得先说清楚第一单选模式下用户聚焦后可以直接打字此时输入框会替代选中文本的位置。如果你之前已经选中了一个值再聚焦输入输入框里默认显示的是当前选中的 label用户可以直接在此基础上追加文字筛选。第二clearable的 x 并不是一直显示的。在单选模式下只有当组件内有选中值并且鼠标移入hover到整个选择器外层时x 才会出现。这是 Element-ui 一种比较克制的展示策略避免选择器右边一直挂着一个默认不可用状态的图标干扰视线。第三在多选模式下清空行为会发生变化。每个选中的 tag 右上角有一个独立的小 x可以单独移除而clearable产生的 x 图标则会出现在最右侧点击后会一次性清空所有已选中的 tag。这俩很容易搞混如果用户只想删掉其中一个点到最右侧的 x所有 tag 都没了很容易误操作。明白了这些交互细节后面再聊原理、踩坑和进阶用法就不会觉得突兀了。2. filterable 筛选机制拆解默认行为、filter-method 与远程搜索filterable用起来简单但要想在真实项目里不出 bug、不卡顿还是得搞清楚它的内部逻辑。Element-ui 的 el-select 在开启 filterable 后实际上是在内部渲染了一个 input 输入框并用query来追踪用户的输入内容。每次 input 内容变化就会走一遍筛选逻辑把匹配的 el-option 保留下来。2.1 默认情况下 Element-ui 到底是怎么匹配的我们先从默认的匹配行为说起。Element-ui 在内部实现了一个默认的 filterMethod它的逻辑核心大概是filterMethod(query, option) { return option.label.toLowerCase().indexOf(query.toLowerCase()) -1; }也就是说默认匹配做的是三件事把选项的label转成小写把用户输入的query也转成小写判断label里是否包含query这个子串。这在大多数中文业务场景下是很够用的。比如下拉选项的 label 是华东-供应链-仓配中心用户输入华东能匹配输入供应链也能匹配输入仓配还能匹配。它做的不是前缀匹配而是子串包含匹配模糊程度刚刚好符合后台管理系统里记得什么关键词就搜什么关键词的直觉。但这里有两个隐含的坑。第一个坑是它匹配的是label不是value。如果你给 el-option 的 label 写的是华东-供应链-仓配中心value 绑定的是一个 id那么用户搜华东没有任何问题但如果你为了让接口提交方便把 label 和 value 绑成了同一个字段比如 value 直接就是 name那么当名称变更时老数据的回显就会被新名称污染。这个问题在后面的回显章节会详细说。第二个坑是默认的匹配逻辑没有对中文输入法做特殊优化。用户用拼音输入法打字时在拼音组合过程中input 事件会不断触发组件也会不断用zhangsan这种中间态去过滤选项结果就是下拉列表在拼音还没拼完的时候就已经开始跳来跳去了。如果你面对的是纯本地的全量筛选这个现象还能忍如果是远程搜索就会导致输入法组词过程中频繁触发接口请求。后文我会给出一个基于 composition 事件的处理思路。2.2 用 filter-method 接管筛选逻辑的正确姿势默认的包含匹配不能满足所有业务。我给你举个例子选项 label 是部门名称财务部但部门还有一个编码是CW2024用户平时更习惯输入编码来找部门。如果只用默认匹配输入CW2024是匹配不到任何东西的因为 label 里没有这段字符串。这种场景就要用filter-method自定义筛选逻辑了。这个属性接收一个方法方法的签名是(query, option)你返回true表示这个选项保留返回false表示过滤掉。实现上面那个编码可搜的需求可以这样写template el-select v-modeldeptId filterable :filter-methodfilterDept placeholder请输入部门名称或编码 el-option v-foritem in deptList :keyitem.id :labelitem.name :valueitem.id :codeitem.code / /el-select /templatemethods: { filterDept(query, option) { if (!query) return true; const keyword query.toLowerCase(); return ( option.label.toLowerCase().includes(keyword) || option.code.toLowerCase().includes(keyword) ); } }这段代码里我利用了 el-option 支持自定义属性的特性把code挂到了 option 上然后自定义 filterMethod 里同时判断 label 和 code。业务需求可以变得很复杂比如名称支持拼音首字母搜索也可以在 option 上挂一个pinyin字段然后让筛选逻辑去匹配这个字段。总之filterMethod 就是你把筛选逻辑从框架默认接管到自己手里的通道。不过要提醒一点使用自定义 filterMethod 时query是由组件内部维护的你只能在筛选函数里读取它不能直接在外层改它。如果你需要跟踪用户输入的原始值比如要在筛选的同时做别的联动那么更好的选择是你自己的搜索输入框 外部 query 变量。这个我们放到后面实战案例里一起说。2.3 remote 远程搜索选项不落地全靠接口实时拉如果说filter-method是本地筛选的进阶那么remote就是另一个维度本地根本不全量持有选项数据每次搜索都是向后端发起请求然后把返回结果渲染成下拉选项。这种模式一般在两种情况下用选项数据量太大比如几万条本地一次性渲染会造成明显卡顿选项数据需要实时查询比如搜索用户的场景后端要求必须传关键字才能返回结果。远程搜索的写法是这样的template el-select v-modeluserId filterable remote clearable reserve-keyword :remote-methodsearchUser :loadingsearching placeholder请输入姓名、工号或手机号搜索 el-option v-foritem in userOptions :keyitem.id :label${item.name}${item.employeeNo} :valueitem.id / /el-select /template注意两个前提使用 remote 时必须同时开启filterable必须提供remote-method方法。remote-method会在用户输入时被调用参数就是输入框里的当前文本。我在项目里用的是这样一个searchUsermethods: { async searchUser(query) { if (query ) { this.userOptions []; return; } this.searching true; try { const params { keyword: query, pageSize: 20 }; const res await fetchUserList(params); this.userOptions res.rows; } finally { this.searching false; } } }这里有两个经验值得说第一query 为空字符串时我直接清空下拉列表而不是默认发起一次无关键字全量查询。因为远程搜索场景下用户没有输入就弹出一大坨数据意义不大而且可能触发后端慢查询。第二接口调用前把searching置为 true配合 el-select 上的loading属性下拉框里会显示一个 loading 状态等接口返回后再置回 false。这个细节看似不起眼但没有它的话用户快速打字时下拉列表不会反馈正在查询体验会差很多。2.4 本地筛选在大数据量下的性能隐患如果你拿着filterable不加思考地套在几万条选项上你会发现在输入文字的那一刹那页面有明显的掉帧感。原因很好理解Element-ui 内部在 query 变化时会对所有 option 做一次遍历筛选然后更新下拉列表的 DOM。选项越多这个过程的计算量越大。我实测过两千条以内的选项用默认 filterMethod 基本无感超过五千条会出现可感知的延迟上万条就会明显卡顿。如果项目里确实需要一次加载全量数据且数量很大我的建议是不要死磕 el-select换成支持虚拟滚动的第三方选择器或者干脆改造成远程搜索让后端按关键字过滤前端只渲染二三十条结果性能问题直接就没了。远程搜索还有一个隐藏的好处数据是按需拉取的意味着前端每次拿到的都是最新数据。部门名称变了、用户离职了搜索出来的结果永远是实时状态不会像本地全量快照那样越积越旧。所以在我的项目里凡是我判断选项规模会膨胀到几千上万的都会主动往远程搜索的方向设计而不是为了省事把所有数据一股脑塞给 el-select。3. clearable 清空功能的显示规则、事件联动与表单校验clearable和filterable常一起出现但 clearable 的细节往往被忽略。很多人在项目里只是加了一个clearable结果发现点击 x 之后联动逻辑没触发、表单校验没跑、下拉里显示的还是搜索时的残留数据于是开始怀疑这个属性是不是坏了。其实不是坏了是没搞明白它的触发机制。3.1 清空按钮什么时候出现什么时候消失clearable 的显示规则前面简单提过这里再展开说单选模式下只有当前选中值非空并且鼠标 hover 到 el-select 外层容器时右侧才会出现 x 图标。下拉面板处于展开状态时即使鼠标没悬停x 也可能出现因为此时组件处于 focus 状态视觉上也会把它当作可操作状态。多选模式下除了每个 tag 右侧的小 x 之外容器最右侧还会有一个清空所有 tag 的 x同样需要 hover 才能看到。当下拉选项为空、没有选中值时无论怎么 hover 都不会出现 x。这条规则在移动端会被放大成一个问题触屏设备没有 hover 状态x 可能一直不出现用户找不到清空入口。如果你的后台系统有移动端访问需求我的建议是不要完全依赖 clearable 的 x可以额外在 el-select 后面放一个清空按钮或者切换到多选模式让用户通过删除 tag 来清理。3.2 clear 事件、change 事件与 v-model 的关系点击 x 清空之后到底发生了什么这里有一个容易混淆的点clear事件和change事件的触发关系。El-select 的clear事件是 clearable 专属的点击清空按钮时触发。它会做两件事把内部的当前值置空然后触发clear事件。与此同时change事件是否触发取决于值是否真的发生了变化。如果清空之前选中了某个值点 x 后值从非空变成了空那么change事件也会触发如果值本来就是空x 根本不会显示自然也谈不上触发 change。所以你在业务里做清空后联动时要有意识地判断该监听哪个事件methods: { handleClear() { // 点 x 后立即触发适合做重置外部状态 this.filterForm.userName ; this.loadList(); }, handleChange(val) { // 值真正变化时触发适合做提交前联动 if (val ) { // 说明清空操作导致值变为空 } } }一个很容易踩的坑是在handleClear里读this.value以为还是旧值但实际上 v-model 对应的值在点 x 的瞬间已经被清空了。如果你的联动逻辑依赖清空前选中的值必须在点 x 之前把它缓存到别处否则你在 clear 回调里读到的只会是一个空值。3.3 表单校验里clearable 要怎么配合后台系统几乎离不开表单校验。el-select 在 el-form 里的校验触发时机默认是change所以加不加 clearable对选择后校验是没有影响的。但清空之后校验的触发就要看你的 rules 怎么写了。我见过很多同学这样写rules: { ownerId: [ { required: true, message: 请选择负责人, trigger: change } ] }这样写的情况下用户选中一个负责人后正常校验通过然后点 x 清空因为值变了change 触发了required 校验也会立刻触发弹出请选择负责人的提示。这通常是我们想要的行为。但如果用户打开页面时本来就没选过任何值点 x 是无意义的因为 x 不会出现这也不会触发任何校验。如果你的业务允许用户清空同时又希望清空后不做即时校验等提交时再统一校验那可以给 select 去掉 change 触发或者在校验前手动调用clearValidate。我这里更推荐的做法是表单提交时统一走this.$refs.form.validate()不依赖随时触发的 change 校验。这样 clearable 清空后用户可以继续编辑其他字段等真正点提交时才被拦住提示更明确。3.4 多选模式下 clearable 的特殊行为多选场景下clearable 的行为和单选有一些差异。多选的 el-select 开启 clearable 后用户删除单个 tag 是走 tag 上的 x这不是 clear 事件只有点击最右侧那个清空所有的 x才会触发 clear 事件。所以如果你在 clear 事件里做了重置列表的处理用户删除单个 tag 时是不会触发这个重置的。另外多选模式下清空所有 tag 后v-model 的值变成空数组[]这和单选清空后变成或null不一样。业务代码里如果要判断是否已清空需要根据单选/多选来写不同的判断条件不能简单用 falsy 判断一把梭。这个细节排起错来很隐蔽因为控制台打印空数组和空字符串看起来完全不一样。4. 实战案例一个可筛选可清空的负责人选择器聊完原理我们用真实的业务场景把 filterable、clearable 以及 remote 串起来走一遍。这个案例是我们的工单分配页面核心需求是选择一个负责人负责人数据量约三万人支持按姓名、工号、手机号检索选中后允许一键清空重新选择。4.1 需求本质选人不是翻通讯录在这个需求里选人的本质不是让用户在一个三万人列表里翻找而是让用户尽量少打字、快速定位、快速确认。所以我们最终的产品交互定为弹出一个远程搜索下拉用户输入姓名/工号/手机号任意片段后端接口返回匹配的前 20 条用户键盘选择回车确认之后如果需要改选点 x 清空再来一次。因为这个场景里当前选中的人可能不在默认列表里编辑回显时尤其如此所以我们设计了一个初始化回显兜底逻辑如果编辑时 passed 进来一个ownerId页面加载的同时会根据 id 调一次 根据 id 查询用户 的接口把该用户塞进userOptions里保证 el-select 能正常显示 label 而不是显示一坨 id。4.2 完整实现代码先看模板部分template div classassign-form el-form refassignForm :modelform :rulesrules label-width90px el-form-item label负责人 propownerId el-select v-modelform.ownerId filterable remote clearable reserve-keyword :remote-methodremoteSearchOwner :loadingsearching placeholder请输入姓名、工号或手机号 stylewidth: 320px clearhandleClearOwner el-option v-foritem in userOptions :keyitem.id :label${item.name}${item.employeeNo} :valueitem.id / /el-select /el-form-item /el-form /div /template数据部分data() { return { form: { ownerId: // 当前选中的负责人 id }, rules: { ownerId: [{ required: true, message: 请选择负责人, trigger: change }] }, userOptions: [], // 下拉候选项 searching: false, // 远程搜索 loading clearSearchQuery: // 备用的外部 query 变量 }; }方法部分methods: { async remoteSearchOwner(query) { // 输入为空时直接清空下拉候选项 if (query ) { this.userOptions []; return; } this.searching true; try { const res await fetchOwnerList({ keyword: query, pageSize: 20 }); this.userOptions res.rows; } catch (e) { this.userOptions []; } finally { this.searching false; } }, async loadOwnerNameById(ownerId) { // 回显兜底通过 id 拉取对应负责人信息保证 label 能正常显示 if (!ownerId) return; const res await fetchOwnerById(ownerId); if (res) { this.userOptions [{ id: res.id, name: res.name, employeeNo: res.employeeNo }]; } }, handleClearOwner() { // 清空后重置 related 字段比如之前根据负责人带出的部门 this.form.deptId null; this.userOptions []; } }4.3 实战中值得反复确认的 4 个细节这个案例跑起来之后有四个细节是当时反复验证过的分享给你第一reserve-keyword的作用。默认情况下remote 搜索结束后如果用户失去焦点搜索关键字会被清空。如果业务希望用户清空选中项后下拉面板重新打开时还保留上一次搜索的关键字就设reserve-keyword。这个属性是远程搜索场景里特别容易被忽略的但它直接决定了用户二次编辑时还要不要重新打字。第二回显兜底不能省。我见过太多项目里 el-select 远程搜素编辑时明明在表格里能看到用户名字点开编辑却变成一串 id。原因就是 userOptions 里没有当前选中值对应的 optionel-select 只能退而显示 value。解决方式就是我上面的loadOwnerNameById一定要在初始化时把当前值对应的 label 塞进 options 里。第三query 接口最好做防抖。远程搜索场景下用户打张三两个字input 事件会触发两次甚至更多次如果每次都立刻发请求请求数量会翻倍。我建议在调用 remote-method 时做一层 200ms 左右的防抖处理既不会让用户觉得响应变慢又能显著降低后端压力。第四清空后的下拉列表状态要主动管理。点 x 触发handleClearOwner后userOptions被清空是合理的因为用户此时没有输入任何关键词。但如果你的产品希望清空后仍然展示默认推荐列表就要在handleClear里调用一个拉取默认推荐列表的接口而不是直接清空。这个要根据具体产品逻辑决定没有标准答案但一定要主动处理别指望 Element-ui 帮你自动恢复。5. 项目里实际踩过的坑从输入残留到远程搜索状态重置讲完正面案例接下来这部分是我特别想写的。filterable 和 clearable 看着简单真到线上环境里各种奇怪现象层出不穷。我梳理了四个最典型的坑每一个都是我或同事实打实踩过的按排查链路写出来。5.1 filterable 输入框里的关键词残留有一个很典型的现象用户打开下拉输入张筛选出来一批张三、张力、张伟然后直接点了其中一个选项组件正常回显张三。但当你再次展开下拉时输入框里竟然还留着上次的张字筛选结果也停留在姓张的列表上完全不是你希望看到的全量列表。这个问题的原因是filterable 开启后el-select 内部的 query 会跟随输入变化选中某个选项时组件并不一定会把 query 重置为空。旧版本里表现得尤为明显。解决办法有几种升级 element-ui 到较新的 2.15.x 版本许多旧版 footer 的 query 残留 bug 已经被修掉在visible-change回调里当下拉面板关闭时手动把组件内部的 query 清空可以结合 ref 调用内部方法如果你用了自定义 filter-method务必在外层维护 query 变量并在visible-changefalse时主动重置它。我这里最推荐的做法是使用visible-change配合nextTick把内部状态归位实测在生产环境里最稳。5.2 清空后 placeholder 不出现或者显示成一串值有段时间我遇到一个诡异问题加了 clearable 后用户点 x 清空选择器并没有变成带 placeholder 的空状态而是显示了一段很奇怪的内容——看起来是上次选中项的 id。排查链路是这样的先打印 v-model 绑定的值发现确实是空字符串然后检查userOptions发现这个空值在 options 里找不到对应项最后发现是回显逻辑有问题——页面初始化时我给 value 赋了 id但没有把对应的 option 数据填进 options 里。el-select 在找不到匹配 option 时就尝试把 value 本身当作 label 渲染出来了。这个坑和远程搜索回显是同一个根因。所以不管你有没有用 clearable只要用了远程搜索都必须保证当前值能映射到一条 option。否则一旦数据源变化或者回显时序出错页面上就会莫名其妙显示 id用户看到的第一反应就是系统出 bug 了。5.3 远程搜索下点 x 清空后列表状态没有重置clearable 的 x 点击后remote-method 不会被触发。这句话说起来简单但线上很少有人意识到它会带来连锁问题。我们的一个审批页面里负责人下拉用的就是远程搜索。用户输入张拉出来一批结果然后因为别的考虑不选了点 x 清空。之后他再次点开下拉发现列表仍然停留在张的搜索结果但输入框里已经没有任何文字看起来就是一个空输入框 一堆姓张的人。原因很简单x 清空的只是选中值remote-method 并没有被调用所以 userOptions 里保留的还是上一次搜索的产物。解决方式是在clear回调里主动重置搜索列表handleClear() { this.userOptions []; this.keyword ; }如果你希望清空后重新展示默认的全量列表就把清空 userOptions 改为调用拉取默认列表的接口。注意reserve-keyword已开启时清空后输入框里可能仍然保存着上次的关键字这两种配置的视觉效果完全不同要和产品确认清楚。5.4 下拉面板错位和宽度不一致filterable 开启后el-select 的下拉层是一个独立的 popper偶尔会出现错位或者宽度跟选择器宽度不一致的问题。我们遇到过一种比较典型的情况页面里 el-select 放在 el-table 的某一行单元格里table 外层有横向滚动条滚动后下拉层没有跟着组件一起移动位置就偏了。排查下来主要是两个原因一是外层容器加了overflow: hidden或者overflow: autopopper 定位计算到了错误的参考父级二是popper-append-to-body被显式设置成了 false导致下拉层被渲染到了受限容器内部。我当时的修复是确认 el-select 的popper-append-to-body保持默认 true同时给外层表格的滚动容器加上overflow-anchor: none之类的兜底样式。如果还是错位还可以在 visible-change 为 true 的下一个 tick 里手动触发一次 popper 更新虽然丑但在老项目里应急很管用。6. 与 el-table 配合的体验优化从筛选下拉到行展开联动最后聊一个搜索热词带来的延展话题Element-ui 表格里面的行可以收起来这类交互和 el-select 的组合其实很值得琢磨。我在后台项目里经常把 el-select 放到表格的行内或筛选栏里配合行展开、行收起整体体验可以做得非常顺滑。6.1 表格筛选栏里的可筛选可清空下拉列表页顶部的筛选区是 el-select 的高频使用场景。比如一个工单列表筛选条件里有状态、负责人、优先级状态和优先级选项可能就几个不需要 filterable但负责人如果来自一个上千人的大表就必须用 filterable 了。我在筛选区里给负责人下拉加了 filterable clearable remote 三件套配合重置按钮整个筛选体验非常一致输入关键字缩小范围 - 选中 - 点 x 或重置按钮把条件清空。这里有个小经验筛选区的清空最好在重置按钮里统一处理同时调用 el-select 的 clear 行为而不是只把绑定值置空。因为只置空值不会触发 clear 事件可能导致其他筛选条件没有被联动清理。6.2 行展开与选择器状态联动el-table 的展开行功能官方叫typeexpand可以让行的更多内容在点击后展开再点一下收起。我们有一个项目是这样用的表格主行只显示工单号、标题、状态展开后显示负责人、描述、操作记录其中负责人就是一个 el-select支持 filterable 远程搜索修改。这里有个很容易踩的坑展开行的内容如果用了 v-if 条件渲染行收起时 el-select 组件会被销毁再次展开时重新创建。如果绑定的 value 已经通过接口修改过重新创建后由于 options 里没有对应选项就会出现暂时显示 id 的情况。我的处理方式是展开行内部维护一个独立的回显方法在行展开前根据当前行的 ownerId 预先拉取 owner 信息塞进 options保证用户每次展开看到的都是正常的人名。6.3 把可收起的思路延伸到更多列表交互其实表格行可以收起来这个交互表达的核心思想是让页面信息密度可调节用户可以主动折叠不需要的细节。这个思路和 clearable 的让用户主动归零本质上是一回事。我做后台系统久了越来越觉得好用的组件交互都遵循同一个原则给用户一个明确的退出路径。展开行可以收起搜索关键字可以被清掉选中项可以一键清除这些都是退出路径的体现。所以你在做任何列表类页面的时候不妨多问自己一句用户能不能在不需要某个信息时一键让它消失如果不能这个交互设计就有改进空间。el-select 的 filterable 和 clearable 就是这句话非常好的注脚。我在实际项目里慢慢形成了一个习惯凡是下拉选项超过 15 个默认就加 filterable凡是用户有可能选错或改选的下拉默认就加 clearable同时把 clear 事件联动想清楚。这两个属性加起来不过几个字母给用户省下的时间却非常可观。如果你的项目里还有哪里在用长长的下拉列表硬翻不妨今天就去加上这两个属性试试大概率会回来感谢我。