首页 / 资讯中心 / 文章详情

element-react Select 组件详解:下拉选择、多选、过滤与远程搜索的完整实践指南

element-react Select 组件详解:下拉选择、多选、过滤与远程搜索的完整实践指南 ★ FEATURED ARTICLE
前端UI组件设计系统【免费下载链接】element-reactElement UI项目地址https://gitcode.com/gh_mirrors/el/element-react点击查看免费下载本文基于 element-react 官方文档 Selecten-US 展开系统讲解Select组件从基础单选、禁用、可清空、多选、自定义模板、分组到本地过滤与远程搜索的全部用法并逐条对照 src/select 下的源码实现帮助你既会用、又知其所以然理解每个属性在源码中的实际作用点、事件的真实触发时机与回调参数以及空态文案、键盘导航等文档未展开的底层行为。组件概述与源码结构当可选项数量较多时Select使用下拉菜单来展示并选择目标项是表单中替代原生select的核心控件。组件由三个文件构成src/select/Select.jsx主组件负责展开/收起、值同步、过滤、远程搜索、键盘导航等全部核心逻辑src/select/Option.jsx单个选项支持value、label、disabled、自定义模板src/select/OptionGroup.jsx选项分组容器以label标注组名src/select/index.js导出入口通过Select.Option Option、Select.OptionGroup OptionGroup把两个子组件挂载为静态属性因此可以直接以Select.Option、Select.OptionGroup的形式使用。从渲染结构看Select.jsx 的 renderSelect由三部分组成多选模式下的 Tag 区域el-select__tags内部还嵌入了一个过滤用input一个Inputrefreference负责展示当前选中项的label与占位符下拉弹层el-select-dropdown包裹在Transition中选项列表由Scrollbar承载直接渲染this.props.children即Option/OptionGroup。两个值得注意的实现细节弹层的定位基于popper.js在过渡动画进入时通过onEnter实例化Popper动画结束后在onAfterLeave中销毁避免常驻内存点击组件外部自动收起下拉由react-click-outside实现Select在文件末尾被ClickOutside高阶组件包裹Select.jsx#L982。另外Select通过contextTypes读取form上下文Select.jsx#L960-L962值变化时会调用form.onFieldChange()通知所在表单这也是它能与 Form 组件联动的底层原因。基本用法value是当前选中项对应的Option的 value。完整示例与文档一致constructor(props) { super(props); this.state { options: [{ value: Option1, label: Option1 }, { value: Option2, label: Option2 }, { value: Option3, label: Option3 }, { value: Option4, label: Option4 }, { value: Option5, label: Option5 }], value: }; } render() { return ( Select value{this.state.value} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} / }) } /Select ) }源码层面的工作机理每个Option在挂载时会向父级Select注册自身Option.jsx#L25-L35 中调用parent().onOptionCreate(this)卸载时反注册Select把所有Option实例保存在state.options数组中这是后续值匹配、键盘导航、过滤统计的数据基础。当外部受控的value变化时handleValueChange在options中按option.props.value value精确匹配出选中项并把输入框显示文本设为selected.props.label || selected.props.value。Option的currentLabel决定了选项的显示文本优先取label省略时若value是 string 或 number 则直接显示 value这正对应属性表中 “label 省略时与 value 相同” 的说明。Select是受控组件父组件更新valueprop 后componentWillReceiveProps同步到内部 state 并重新执行handleValueChange而用户在 UI 上的选择则通过onChange把新值抛给父组件形成典型的受控闭环。禁用选项与禁用整个组件禁用单个选项将Option的disabled设为true即可禁用该选项constructor(props) { super(props); this.state { options: [{ value: Option1, label: Option1 }, { value: Option2, label: Option2, disabled: true }, { value: Option3, label: Option3 }, { value: Option4, label: Option4 }, { value: Option5, label: Option5 }], value: }; } render() { return ( Select value{this.state.value} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} disabled{el.disabled} / }) } /Select ) }禁用整个组件把Select的disabled设为true可以禁用整个组件constructor(props) { super(props); this.state { options: [{ value: 选项1, label: 黄金糕 }, { value: 选项2, label: 双皮奶 }, { value: 选项3, label: 蚵仔煎 }, { value: 选项4, label: 龙须面 }, { value: 选项5, label: 北京烤鸭 }], value: }; } render() { return ( Select value{this.state.value} disabled{true} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} / }) } /Select ) }源码中disabled的三层作用点可以印证上述行为点击选中被拦截Option的selectOptionClick同时检查自身disabled与父级Select的disabled任一为真都不触发onOptionClick展开被拦截toggleMenu在disabled为真时直接返回下拉不会打开渲染层面底层Input传入disabled{disabled}输入框本身不可交互。此外键盘上下导航时也会跳过禁用的选项见后文 键盘交互细节。可清空单选clearable给Select设置clearable属性后会出现清除图标注意clearable仅对单选生效constructor(props) { super(props); this.state { options: [{ value: Option1, label: Option1 }, { value: Option2, label: Option2 }, { value: Option3, label: Option3 }, { value: Option4, label: Option4 }, { value: Option5, label: Option5 }], value: }; } render() { return ( Select value{this.state.value} clearable{true} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} / }) } /Select ) }“仅单选生效” 这一约束来自showCloseIcon只有当clearable inputHovering !multiple 存在已选 option四个条件同时成立时图标才会切换为circle-close并挂上点击监听。点击清除图标触发deleteSelected清空selected与selectedLabel、收起下拉然后依次回调onChange()与onClear()同时通知表单上下文onFieldChange()。多选模式multiple多选模式使用 Tag 展示已选项此时value为已选项的数组constructor(props) { super(props); this.state { options: [{ value: Option1, label: Option1 }, { value: Option2, label: Option2 }, { value: Option3, label: Option3 }, { value: Option4, label: Option4 }, { value: Option5, label: Option5 }], value: [] }; } render() { return ( Select value{this.state.value} multiple{true} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} / }) } /Select ) }多选模式下的源码行为选中项以数组保存构造时multiple为真即初始化selected: []见 Select.jsx#L82-L85每个选项点击后在数组中做增删onOptionClick已选则移除未选则追加输入框左侧渲染 Tag 列表render 中的 el-select__tags 部分每个 Tag 可关闭closable{!disabled}点击关闭图标走deleteTag从数组中删除该选项并回调onRemoveTag(tag.props.value)键盘 BackspacekeyCode 8可删除最后一个 TagdeletePrevTag借助hitState给最后一个 Tag 一个短暂的高亮“命中”态后再弹出与文档演示的交互一致每次选择变化onChange回调的参数是已选 value 的数组多选时见 onSelectedChange。自定义选项模板可以为选项自定义 HTML 模板把定制内容作为Option的子节点插入constructor(props) { super(props); this.state { cities: [{ value: Beijing, label: Beijing }, { value: Shanghai, label: Shanghai }, { value: Nanjing, label: Nanjing }, { value: Chengdu, label: Chengdu }, { value: Shenzhen, label: Shenzhen }, { value: Guangzhou, label: Guangzhou }], value: [] }; } render() { return ( Select value{this.state.value} { this.state.cities.map(el { return ( Select.Option key{el.value} label{el.label} value{el.value} span style{{float: left}}{el.label}/span span style{{float: right, color: #8492a6, fontSize: 13}}{el.value}/span /Select.Option ) }) } /Select ) }对应实现是 Option 的 renderli内容取this.props.children || span{this.currentLabel()}/span—— 传了子节点就渲染模板否则回退为 label 文本。需要注意过滤匹配用的仍是currentLabel()即label属性而不是自定义模板里的文本因此自定义模板时务必同时传好label否则filterable时可能匹配不到。选项分组OptionGroup使用OptionGroup对选项进行分组其label属性为组名constructor(props) { super(props); this.state { options: [{ label: Popular cities, options: [{ value: Shanghai, label: Shanghai }, { value: Beijing, label: Beijing }] }, { label: City name, options: [{ value: Chengdu, label: Chengdu }, { value: Shenzhen, label: Shenzhen }, { value: Guangzhou, label: Guangzhou }, { value: Dalian, label: Dalian }] }], value: }; } render() { return ( Select value{this.state.value} { this.state.options.map(group { return ( Select.OptionGroup key{group.label} label{group.label} { group.options.map(el { return ( Select.Option key{el.value} label{el.label} value{el.value} span style{{float: left}}{el.label}/span span style{{float: right, color: #8492a6, fontSize: 13}}{el.value}/span /Select.Option ) }) } /Select.OptionGroup ) }) } /Select ) }OptionGroup 的实现 很轻量渲染一个el-select-group__wrap的ul组名显示在el-select-group__title中子选项放在嵌套的ul内。需要说明的一点差异文档的 Option Group 属性表中列出了disabled禁用整组但从当前源码看OptionGroup的propTypes只声明了label并未把组级禁用下发给子OptionSelect的键盘导航逻辑中虽然引用了groupDisablednavigateOptions但在当前版本中该标记并无来源组件为其赋值因此组级禁用应视为规划中的能力实际禁用仍建议逐项设置Option的disabled。选项过滤filterable / filterMethod给Select加上filterable即可开启过滤。默认情况下Select会找出所有label包含输入值的选项如果希望使用其他过滤策略可以传入filterMethod—— 它是一个Function在输入值变化时被调用参数为当前输入值constructor(props) { super(props); this.state { options: [{ value: Option1, label: Option1 }, { value: Option2, label: Option2 }, { value: Option3, label: Option3 }, { value: Option4, label: Option4 }, { value: Option5, label: Option5 }], value: [] }; } render() { return ( Select value{this.state.value} filterable{true} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} / }) } /Select ) }过滤的完整调用链onQueryChange分三种情况remote且remoteMethod是函数 → 走远程搜索分支见下节传入了自定义filterMethod→ 直接调用filterMethod(query)把过滤权完全交给业务代码否则执行默认过滤先记录filteredOptionsCount再遍历所有 option 调用option.queryChange(query)。默认过滤的匹配逻辑在 Option.queryChange先把 query 中的正则特殊字符^ ( ) [ ] $ * . ? \ { } |逐个转义再用new RegExp(parsedQuery, i).test(this.currentLabel())做大小写不敏感的“包含”匹配。匹配不上的 option 会把state.visible置为 false渲染时不显示同时让父级filteredOptionsCount减一当该计数归零且处于过滤状态时emptyText返回 locale 中的 “noMatch” 文案英文为 “No matching data”中文为 “无匹配数据”见 en locale 与 zh-CN locale弹层中显示 “无匹配数据” 提示。另外单选过滤模式下打开下拉时输入框会预填当前选中项的 label 作为初始查询onVisibleChange 中query selectedLabel这与原生 select 的“按当前值筛选”体验一致。远程搜索remote / remoteMethod输入关键字后从服务器检索数据。将filterable与remote同时设为true开启远程搜索并传入remoteMethod—— 它同样是一个在输入值变化时被调用的Function参数为当前输入值constructor(props) { super(props); this.state { options: [], states: [Alabama, Alaska, Arizona, Arkansas, California, Colorado, Connecticut, Delaware, Florida, Georgia, Hawaii, Idaho, Illinois, Indiana, Iowa, Kansas, Kentucky, Louisiana, Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana, Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina, North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia, Wisconsin, Wyoming] } } onSearch(query) { if (query ! ) { this.setState({ loading: true }); setTimeout(() { this.setState({ loading: false, options: this.state.states.map(item { return { value: item, label: item }; }).filter(item { return item.label.toLowerCase().indexOf(query.toLowerCase()) -1; }) }); }, 200); } else { this.setState({ options: [] }); } } render() { return ( Select value{this.state.value} multiple{true} filterable{true} remote{true} remoteMethod{this.onSearch.bind(this)} loading{this.state.loading} { this.state.options.map(el { return Select.Option key{el.value} label{el.label} value{el.value} / }) } /Select ) }与远程搜索相关的三个源码机制300ms 防抖remote模式下输入变化会经过防抖后再触发查询。debounce()返回this.props.remote ? 300 : 0构造函数中用throttle-debounce的debounce包装输入处理多选分支的内联input的onChange同样使用该延迟render 中的 setTimeout避免每次击键都发起请求空查询不展示空态远程模式下若用户把查询清空voidRemoteQuery会被置真onQueryChange此时emptyText返回false下拉层不渲染 “无数据” 之类的提示等待服务器返回新选项loading 状态loading为真时选项列表整体隐藏render 中 View 的 show 条件并在下拉中显示 locale 的 “loading” 文案英文 “Loading”、中文 “加载中”。属性与事件参考以下 API 表完整继承自官方文档en-US 版zh-CN 版 内容相同。Select 属性属性说明类型可选值默认值multiple是否启用多选boolean—falsedisabled是否禁用整个 Selectboolean—falsesize输入框尺寸stringlarge / small / mini—clearable单选时是否可清空boolean—falsemultipleLimitmultiple为 true 时用户最多可选的项数设为 0 表示不限制number—0name隐藏 input 的 name 属性string——placeholder占位文本string—Selectfilterable是否可过滤boolean—falseallowCreate是否允许创建新条目使用前必须开启filterableboolean—falsefilterMethod自定义过滤方法function——remote选项是否来自服务器boolean—falseremoteMethod自定义远程搜索方法function——loading是否正在从服务器加载数据boolean—falseloadingText远程加载时显示的文本string—LoadingnoMatchText过滤无匹配时显示的文本string—No matching datanoDataText无选项时显示的文本string—No datapopperClass下拉层的自定义类名string——Select 事件事件名说明参数onChange选中值变化时触发当前选中值onVisibleChange下拉出现/消失时触发出现时为 true否则为 falseonRemoveTag多选模式下移除某个 tag 时触发被移除 tag 的 valueonClear点击 clearable Select 的清除图标时触发-OptionGroup 属性属性说明类型可选值默认值label组名string——disabled是否禁用该组内所有选项boolean—falseOption 属性属性说明类型可选值默认值value选项的值string / number / object——label选项的标签省略时与 value 相同string / number——disabled选项是否禁用boolean—false属性表与当前源码的差异说明为保证与仓库实现严格对齐以下差异值得注意均以当前源码为准Select.propTypes 实际声明了value、size、disabled、clearable、filterable、loading、remote、remoteMethod、filterMethod、multiple、placeholder以及事件回调onChange、onVisibleChange、onRemoveTag、onClear而multipleLimit、allowCreate、loadingText、noMatchText、noDataText、popperClass未出现在当前源码的propTypes中也未发现对应的限制/渲染逻辑name在渲染中被硬编码为namenamerender 中的 Input。空态/加载文案实际取自 i18n 的el.select命名空间zh-CN 为 “加载中 / 无匹配数据 / 无数据 / 请选择”en 为 “Loading / No matching data / No data / Select”因此属性表中placeholder默认值 “Select” 与英文 locale 一致中文环境下默认占位为 “请选择”。size的取值large/small/mini与源码中的高度映射一致sizeMap 分别为 42 / 30 / 22默认 36见 resetInputHeight。onChange的实际调用比表格描述携带更多信息多选时回调onChange(value 数组, Option 实例数组)单选时回调onChange(value, Option 实例)onSelectedChange第二个参数可用于直接取 label。onVisibleChange在内部visible状态变化时触发componentWillUpdate参数即布尔值。键盘交互细节除鼠标外Select内置了完整的键盘操作单选输入框的 onKeyDown 与 多选内联输入的 onKeyDown按键行为源码Enter13选中当前 hover 的选项selectOption↑38/ ↓40上/下移动 hover循环切换navigateOptionsEsc27/ Tab9收起下拉onKeyDown 分支Backspace8多选删除最后一个 Tag先高亮命中态deletePrevTag导航时的三个细节hover 移动到disabled、groupDisabled或过滤后不可见的选项上时会自动跳过递归调用自身直到落在合法选项上navigateOptions 的 skip 逻辑每次移动后调用resetScrollTop用选中项与弹层的getBoundingClientRect差值滚动dropdownUl保证 hover 项始终可见关闭下拉时会记录选中项相对弹层底边的溢出量bottomOverflowBeforeHiddenonVisibleChange下次打开时自动补滚打开分支避免长列表打开后看不到当前选中项。小结Select通过 “Option 自注册 受控 value 匹配” 实现了灵活的选项管理基础单选、多选、分组、自定义模板分别由value、multiple、OptionGroup和Option子节点驱动filterable提供本地/自定义过滤remote remoteMethod配合 300ms 防抖与loading状态支撑服务器检索。属性与事件以 Select.jsx 的 propTypes 和 Option.jsx 的 propTypes 为当前实现的准确基准文档 API 表中尚未落地的条目如multipleLimit、allowCreate、popperClass在使用前建议先核实现源码避免预期行为缺失。赞分享前端UI组件设计系统【免费下载链接】element-reactElement UI项目地址https://gitcode.com/gh_mirrors/el/element-react点击查看免费下载相关推荐Element Select 下拉选择器完整实战指南基础用法、远程搜索与源码实现解析Element Select 下拉选择器完整实战指南基础用法、远程搜索与源码实现解析 ElementA Vue.js 2.0 UI Toolkit for前端UI组件设计系统antd Select 组件完全指南选项下拉框的 API、搜索、多选与最佳实践antd Select 组件完全指南选项下拉框的 API、搜索、多选与最佳实践 导读 Select https://link.gitcode.com/i/75前端UI组件设计系统Shoelace选择器Select下拉选择组件详解Shoelace选择器Select下拉选择组件详解 Shoelace选择器是现代Web开发中功能强大的下拉选择组件提供了丰富的自定义选项和优雅的交互体验。这UI组件前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站