Ant Design Mentions 组件实战指南:输入框提及(@)交互、数据加载与高级定制全解析

Ant Design Mentions 组件实战指南:输入框提及(@)交互、数据加载与高级定制全解析 Ant Design Mentions 组件实战指南输入框提及交互、数据加载与高级定制全解析【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-designMentions提及是 Ant Design 数据录入体系中的输入 联想复合组件用于在输入过程中通过等触发字符呼出候选列表、快速选中并回填广泛应用于发布、聊天、评论等场景。本文基于 ant-design 仓库中 components/mentions/index.zh-CN.md 的官方 API 文档并结合该组件完整源码、样式实现与全部官方示例系统讲解其数据源组织、事件流、Form 集成、异步加载、形态变体、语义化样式与主题 Token帮助你从会用进阶到能按需深度定制。Mentions 的核心定位什么时候该用它官方文档对使用场景的描述非常凝练用于在输入中提及某人或某事常用于发布、聊天或评论功能。它本质上是「可编辑文本域 触发字符识别 联想下拉菜单」三者的组合与 AutoComplete 的差异在于Mentions 把输入内容本身当作可提交的值一串含xxx的字符串选中的条目会以纯文本形式回填进输入框再由后端解析提及关系。组件在 antd 中挂载于mentions组件目录下其顶层实现位于 components/mentions/index.tsx。它内部基于rc-component/mentions封装负责补齐主题样式、状态联动、Form 上下文、语义化 classNames/styles、z-index 管理等 antd 能力。快速上手数据源两种组织方式最基础的用法只需给出选项列表即可import React from react; import { Mentions } from antd; import type { GetProp, MentionProps } from antd; type MentionsOptionProps GetPropMentionProps, options[number]; const onChange (value: string) { console.log(Change:, value); }; const onSelect (option: MentionsOptionProps) { console.log(select, option); }; const App: React.FC () ( Mentions style{{ width: 100% }} onChange{onChange} onSelect{onSelect} defaultValueafc163 options{[ { value: afc163, label: afc163 }, { value: zombieJ, label: zombieJ }, { value: yesmeck, label: yesmeck }, ]} / ); export default App;对应可运行示例见 demo/basic.tsx。注意默认值为afc163即预填一段已触发的内容。除options外历史上也支持子组件写法Mentions.Option valueafc163afc163/Mentions.OptionOption由RcMentions.Option直接导出见 index.tsx。但从源码可以明确看到组件在开发环境会通过warning.deprecated(!children, Mentions.Option, options)提示一旦检测到存在children即子组件写法就会在 dev 控制台输出 Mentions.Optionis deprecated. Please useoptionsinstead. 的废弃警告警告机制见 components/_util/warning.ts。因此新代码请统一使用options数组。Option 选项属性参数说明类型默认值value选择时填充的值回填到输入框的内容不含触发符触发符由 prefix 决定string-label选项的标题React.ReactNode-key选项的 key 值string-disabled是否可选boolean-classNamecss 类名string-style选项样式React.CSSProperties-触发、搜索与选择完整事件流Mentions 的交互核心是「输入字符 → 命中触发符 → 触发搜索 → 展示联想 → 选择回填」。对应的核心 API 如下prefix设置触发关键字类型string | string[]默认。传数组即可支持多套触发符如[, #]分别提及用户与话题。split设置选中项前后的分隔符默认 空格。该字符同时是解析文本中提及实体的切分依据。onSearch搜索命中触发符后时触发回调签名(text: string, prefix: string) void第二个参数回传本次命中的具体触发符。onSelect选中选项时触发(option: OptionProps, prefix: string) void。onChange输入值变化时触发(text: string) void其中 text 是包含触发符的整段文本。onFocus / onBlur聚焦与失焦回调。filterOption自定义过滤逻辑false | (input, option) boolean传入false时关闭本地过滤常用于受控 options 或服务端搜索场景。多触发符与动态数据源当使用多个 prefix 且希望不同前缀对应不同候选集时官方示例的做法是维护一个prefix状态并通过onSearch的第二个参数回写当前命中符从而切换 optionsimport React, { useState } from react; import { Mentions } from antd; import type { MentionsProps } from antd; const MOCK_DATA { : [afc163, zombiej, yesmeck], #: [1.0, 2.0, 3.0], }; type PrefixType keyof typeof MOCK_DATA; const App: React.FC () { const [prefix, setPrefix] useStatePrefixType(); const onSearch: MentionsProps[onSearch] (_, newPrefix) { setPrefix(newPrefix as PrefixType); }; return ( Mentions style{{ width: 100% }} placeholderinput to mention people, # to mention tag prefix{[, #]} onSearch{onSearch} options{(MOCK_DATA[prefix] || []).map((value) ({ key: value, value, label: value, }))} / ); };完整示例见 demo/prefix.tsx。这里onSearch的第二个参数会在每次触发符变更时把最新命中符带给开发者从而让 options 跟着当前触发符切换是多命名空间提及的推荐范式。异步加载loading 状态与请求竞态处理真实场景中候选用户通常来自远端接口demo/async.tsx 给出了一份可借鉴的完整方案import React, { useCallback, useRef, useState } from react; import { Mentions } from antd; import debounce from lodash/debounce; const App: React.FC () { const [loading, setLoading] useState(false); const [users, setUsers] useState([]); const ref useRefstring(null); // 用于丢弃过期请求结果 const loadGithubUsers (key: string) { if (!key) { setUsers([]); return; } fetch(https://api.github.com/search/users?q${key}) .then((res) res.json()) .then(({ items [] }) { if (ref.current ! key) return; // 关键旧请求返回时直接丢弃 setLoading(false); setUsers(items.slice(0, 10)); }); }; const debounceLoadGithubUsers useCallback(debounce(loadGithubUsers, 800), []); const onSearch (search: string) { ref.current search; setLoading(!!search); setUsers([]); debounceLoadGithubUsers(search); }; return ( Mentions style{{ width: 100% }} loading{loading} onSearch{onSearch} options{users.map(({ login }) ({ key: login, value: login, label: login }))} / ); };这份示例里有两个工程要点防抖通过 lodashdebounce(loadGithubUsers, 800)合并高频输入触发的请求竞态防护把当前搜索词存入 ref旧请求返回时若发现ref.current ! key则直接丢弃避免快速切换关键词时旧数据覆盖新数据。loading 属性的底层行为loading并非仅仅展示一个加载图标。结合 index.tsx 源码可以确认其内部行为当loading为true时options会被整体替换为[{ value: ANTD_SEARCHING, disabled: true, label: Spin sizesmall / }]filterOption会被替换为恒返回true的loadingFilterOption即搜索命中时不走本地过滤源码 L31-L33、L202-L212传入RcMentions的silent{loading}会压制加载期间的提示输出。也就是说加载期间下拉中只会展示一个禁用态 Spin 占位用户无法选中任何项实现了加载即屏蔽交互的兜底。与 Form 集成回填文本的校验与解析Mentions 可直接作为表单控件使用。onChange产出的是整段文本字符串若要在校验时从整段文本中解析出所有被提及的实体官方提供了静态方法Mentions.getMentions(value, config?)。其调用形态与解析实现可在 index.tsx 中确认Mentions.getMentions (value , config: MentionsConfig {}): MentionsEntity[] { const { prefix , split } config; const prefixList: string[] toList(prefix); return value.split(split).reduce((list, str ) { // 逐个尝试 prefix命中后取去除触发符的剩余内容作为 value ... }, []); };可见其返回数组元素的形态是{ prefix: string, value: string }解析规则是按split分隔整段文本再检查每段是否以某个prefix开头。基于此可轻松实现「至少要提及 N 个用户」之类的表单校验import React from react; import { Button, Form, Mentions, Space } from antd; const { getMentions } Mentions; const App: React.FC () { const [form] Form.useForm(); const checkMention async (_: any, value: string) { const mentions getMentions(value); if (mentions.length 2) { throw new Error(More than one must be selected!); } }; return ( Form form{form} layouthorizontal onFinish{() console.log(submit)} Form.Item namecoders labelTop coders rules{[{ validator: checkMention }]} Mentions rows{1} options{[{ value: afc163 }, { value: zombieJ }, { value: yesmeck }]} / /Form.Item ... /Form ); };该场景的完整可运行版本见 demo/form.tsx。rows用于设定文本域初始行数。组件实例上暴露了两个命令式方法blur()移除焦点、focus()获取焦点可用于外部聚焦/失焦控制。尺寸与形态变体size 与 variant尺寸size支持large/medium/small三档medium 为默认。对应示例 demo/size.tsx。从 index.tsx 看尺寸通过useSize从组件自身属性一路合并到 ConfigProvider 全局上下文命中large/small时分别追加-lg/-sm语义 class从而切换到对应的 padding 与高度变量见下文样式实现的-lg、-sm段。Mentions sizelarge placeholderlarge size / Mentions placeholderdefault size / Mentions sizesmall placeholdersmall size /形态变体variant决定输入框外观形态可选outlined默认描边、filled填充、borderless无边框、underlined下划线。对应示例 demo/variant.tsxMentions placeholderOutlined / Mentions placeholderFilled variantfilled / Mentions placeholderBorderless variantborderless / Mentions placeholderUnderlined variantunderlined /版本线索以当前仓库为准variant属性自 5.13.0 引入underlined形态自 5.24.0 支持从 5.19.0 起可作为全局配置统一下发。样式层在 style/index.ts 中复用了input/style/variants的genOutlinedStyle/genFilledStyle/genBorderlessStyle/genUnderlinedStyle四套变体生成器保证与 Input 组件视觉一致。状态与表单联动status、disabled、readOnly 与后缀校验状态status支持error | warning | success | validating自 4.19.0。可直接传入也可交由 Form.Item 的校验状态自动联动——源码中status会通过FormItemInputContext与 Form 上下文的contextStatus合并得到mergedStatus再经getStatusClassNames追加错误/警告态 class见 index.tsx。例如显式给出错误/警告态Mentions defaultValueafc163 statuserror options{options} / Mentions defaultValueafc163 statuswarning options{options} /完整示例见 demo/status.tsx。disabled / readOnly两者皆可作用于 Mentionsdisabled走 antd 全局DisabledContextContext 传值会与 ConfigProvider 的全局禁用态合并readOnly则表现为可聚焦、不可编辑。官方示例 demo/readonly.tsx 同时展示了两种形态。禁用态样式由genDisabledStyle产出并追加${prefixCls}-disabledclass。allowClear 清除按钮allowClear自 5.13.0 支持默认false。类型上除布尔值外还可传入{ clearIcon?: ReactNode, disabled?: boolean }定制清除图标对象形态的disabled字段自 6.4.0 支持。清除动作触发onClear回调5.20.0 起。配套示例 demo/allowClear.tsxMentions value{value} onChange{setValue} allowClear / Mentions value{value} onChange{setValue} allowClear{{ clearIcon: CloseSquareFilled / }} /内部实现中allowClear 最终会合并 ConfigProvider 的全局allowClear上下文见useAllowClear调用因此可以在全局统一开关清除能力。值得注意清除按钮与校验反馈图标都以suffix后缀形式渲染。源码中当 Form.Item 设置了hasFeedback时会把反馈图标塞入 suffixindex.tsx因此 suffix 语义节点内同时容纳了清除图标与校验反馈图标。高度自适应与弹出层方向autoSize、onResize、placementautoSizeautoSize让文本域随内容自动伸缩可设为布尔值或对象{ minRows: number, maxRows: number }例如{ minRows: 2, maxRows: 6 }。见 demo/autoSize.tsxMentions autoSize style{{ width: 100% }} options{options} /在样式层面组件内部存在一个不可见的mentions-measure测量节点用于撑开实际文本域高度见 style/index.ts 中-measure相关规则保证 autoSize 计算与输入字体完全一致。文本域尺寸变化时触发onResize({ width, height })。placement联想弹出层默认在下方展开bottom可设置为placementtop向上展开适合输入框靠近页面底部、下方空间不足的场景。见 demo/placement.tsx。弹出层的挂载容器默认跟随最近的滚动容器需要手动指定时使用getPopupContainer{() HTMLElement}弹层为空时展示的占位内容由notFoundContent控制默认值为暂无数据——具体实现上会优先取 ConfigProviderrenderEmpty结果再回退到内置 Emptyindex.tsx。此外onPopupScroll5.23.0 起可用于监听下拉滚动实现触底加载更多。自定义弹出层渲染popupRenderpopupRender6.6.0 起接收一个参数——默认渲染出的下拉菜单 React 元素返回你要展示的完整内容适合在菜单前后插入自定义区块如标题栏、分隔线、底部按钮。示例 demo/popupRender.tsx 在菜单上方插入了一个 Custom HeaderMentions style{{ width: 100% }} popupRender{(menu) ( div style{{ padding: 12, fontWeight: 600, color: rgba(0,0,0,.45) }} Custom Header /div Divider style{{ margin: 0 }} / {menu} / )} options{options} /从源码看antd 侧复用了 Select 的usePopupRenderhook 来承接该能力index.tsx之后统一传给底层 RcMentions 的popupRender这保证了 Mentions 与 Select 家族在弹层定制体验上保持一致。Semantic DOMclassNames / styles 语义化定制antd 6.x 为 Mentions 提供了一套稳定的语义化 DOM 结构可以通过classNames与styles精准定制某个内部节点而不必再靠样式覆盖 猜类名语义节点说明root根元素行内 flex 布局、相对定位、内边距与边框样式textarea文本域元素字体、行高、文本输入与背景样式popup弹出框元素绝对定位、z-index、背景、圆角、阴影及下拉选项样式suffix后缀元素含清除按钮等后缀内容的布局与样式两者的类型均为Record语义节点, 样式且支持对象或函数两种传法函数形态的入参为{ props }可依据组件当前 props例如variant filled返回不同样式具体由useMergeSemantic统一合并且会与 ConfigProvider 侧通过 component config 下发的classNames/styles深层合并见 index.tsx。示例 demo/style-class.tsxconst stylesObject: MentionsProps[styles] { textarea: { fontSize: 14, resize: vertical, fontWeight: 200 }, }; const stylesFunction: MentionsProps[styles] (info) { if (info.props.variant filled) { return { root: { border: 1px solid #722ed1 }, popup: { border: 1px solid #722ed1 } }; } }; Mentions {...sharedProps} styles{stylesObject} placeholderObject rows{2} / Mentions {...sharedProps} styles{stylesFunction} variantfilled placeholderFunction /语义节点全景示意与中文说明见 demo/_semantic.tsx其中root / textarea / suffix / popup均自 6.0.0 起支持。这种按语义节点定制的方式尤其适合 badge、错误描边、气泡、弹层头部等细粒度视觉调整。主题变量Mentions 专属 Design TokenMentions 的样式由genStyleHooks(Mentions, ...)产出style/index.ts其组件级 Token 默认值如下Token默认值说明zIndexPopupzIndexPopupBase 50弹出层 z-index比基础弹层高 50避免与其他浮层冲突dropdownHeight250下拉菜单最大高度超过即出现纵向滚动controlItemWidth100菜单项最小宽度itemPaddingVertical(controlHeight - fontHeight) / 2菜单项垂直内边距由控件高度与字高动态推导同时组件从 Input 侧initInputToken继承了paddingInline、paddingBlock、controlHeight等输入型 Token并随尺寸档位-lg/-sm切换对应变量。全局颜色、圆角、阴影则走 antd 通用种子 Token如colorBgElevated、borderRadiusLG、boxShadowSecondary保证与 Select、Input 视觉同源。调试示例 demo/component-token.tsx 演示了如何通过theme定制组件 Token 查看效果。例如调整弹层高度与菜单项宽度可统一作用于所有 Mentions 实例ConfigProvider theme{{ components: { Mentions: { dropdownHeight: 200, controlItemWidth: 120, }, }, }} App / /ConfigProvider除上述专属 Token 外弹层背景、选中项 hover 色、禁用色等可直接复用全局主题变量从而在企业级设计中维持一致的设计语言。API 速查表含版本与全局配置信息以下表格完整继承了官方文档并标注了各属性的引入版本以及是否支持通过 ConfigProvider 全局配置 统一设置。通用属性见 通用属性文档。Mentions 主要属性参数说明类型默认值版本全局配置allowClear可以点击清除图标删除内容boolean \| { clearIcon?: ReactNode, disabled?: boolean }false5.13.0disabled字段 6.4.06.4.0autoSize自适应内容高度可设为true \| false或对象{ minRows: 2, maxRows: 6 }boolean \| objectfalse-×classNames自定义组件内部各语义化结构 class支持对象或函数RecordSemanticDOM, string \| (info: { props }) RecordSemanticDOM, string--6.0.0defaultValue默认值string--×filterOption自定义过滤逻辑false \| (input: string, option: OptionProps) boolean--×getPopupContainer指定建议框挂载的 HTML 节点() HTMLElement--×notFoundContent下拉列表为空时显示的内容ReactNode暂无数据-×placement弹出层展示位置top \| bottombottom-×popupRender自定义下拉菜单渲染(menu: React.ReactElement) ReactNode-6.6.0×prefix设置触发关键字string \| string[]-×split设置选中项前后分隔符string -×size控件大小large \| medium \| smallmedium-×status设置校验状态error \| warning \| success \| validating-4.19.0×validateSearch自定义触发验证逻辑(text: string, props: MentionsProps) void--×value设置值受控string--×variant形态变体outlined \| borderless \| filled \| underlinedoutlined5.13.0underlined5.24.05.19.0onBlur失去焦点时触发() void--×onChange值改变时触发(text: string) void--×onClear点击清除按钮的回调() void-5.20.0×onFocus获得焦点时触发() void--×onResize文本域 resize 回调function({ width, height })--×onSearch搜索命中 prefix时触发(text: string, prefix: string) void--×onSelect选择选项时触发(option: OptionProps, prefix: string) void--×onPopupScroll下拉滚动时触发(event: Event) void-5.23.0×options选项配置Options[][]5.1.0×styles自定义组件内部各语义化结构行内 style支持对象或函数RecordSemanticDOM, CSSProperties \| (info: { props }) RecordSemanticDOM, CSSProperties--6.0.0Mentions 方法名称描述blur()移除焦点focus()获取焦点此外组件还挂载了静态成员Mentions.Option与Mentions.getMentions解析文本中的提及实体便于表单校验场景直接使用。小结从使用到深入Mentions 的全貌可以归纳为三层用法层prefix/options/onSearch/onSelect驱动提及交互配合 Form 与getMentions做回填文本校验工程层loading与防抖、竞态处理支撑异步数据源popupRender、placement、getPopupContainer控制弹层形态定制层variant/size/status外观状态、Semantic DOM 的classNames/styles、以及zIndexPopup、dropdownHeight等组件 Token。如果你正在搭建评论框、IM 消息编辑器或带 能力的内容发布页可以以 demo/basic.tsx 起步再按 demo/async.tsx 接入真实用户搜索最后结合本文的源码级说明在 demo/style-class.tsx 与组件 Token 的基础上完成品牌化视觉收敛。【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考