Ant Design Mentions 组件基本使用指南:从基础 demo 到源码级原理
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
导读
Mentions(提及)是 Ant Design 中用于「在输入中提及某人或某事」的核心录入组件,常见于发布、聊天与评论场景。本文以仓库中的 基本使用 demo 为起点,完整讲解其数据组织方式、事件回调、触发前缀与校验等实战能力,并结合 组件源码 与测试用例深入其底层实现。读完本文,你将掌握 Mentions 的声明式 options 用法、5.1.0 升级要点、静态工具方法getMentions的原理,以及如何与 Form 联动完成提及校验。
一、基本使用:一个完整的 Mentions 示例
仓库中 components/mentions/demo/basic.md 对它的描述只有一句话「基本使用」,但对应的 basic.tsx 是一份可直接运行的完整示例:
import React from 'react'; import { Mentions } from 'antd'; import type { GetProp, MentionProps } from 'antd'; type MentionsOptionProps = GetProp<MentionProps, '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} defaultValue="@afc163" options={[ { value: 'afc163', label: 'afc163' }, { value: 'zombieJ', label: 'zombieJ' }, { value: 'yesmeck', label: 'yesmeck' }, ]} /> ); export default App;这段代码覆盖了 Mentions 最核心的四个使用要素:
- 数据源:通过
options传入候选列表,每一项包含value(选择时填充到输入框的值)与label(建议面板中展示的标题); - 回显值:
defaultValue="@afc163"表示初始文本,当用户输入@前缀时,组件会在光标附近弹出候选面板; - 变更监听:
onChange在文本值改变时触发,回调参数为完整的输入文本字符串; - 选中监听:
onSelect在用户选中某个选项时触发,回调参数为该选项对象。
注意 demo 中通过GetProp<MentionProps, 'options'>[number]提取了选项的元素类型,这样onSelect的参数就能获得完整的 TypeScript 类型推导,这是官方示例中推荐的类型写法。
二、数据驱动的 options 与 5.1.0 用法升级
在 5.1.0 之前,开发者需要手工拼接 JSX 来声明选项;5.1.0 之后官方推荐使用options数组的数据驱动写法,详见 组件文档「5.1.0 用法升级」:
// >=5.1.0 可用,推荐的写法 ✅ const options = [{ value: 'sample', label: 'sample' }]; return <Mentions options={options} />; // <5.1.0 可用,>=5.1.0 时不推荐 🙅🏻♀️ return ( <Mentions onChange={onChange}> <Mentions.Option value="sample">Sample</Mentions.Option> </Mentions> );从源码看,旧写法并未被立即移除,而是通过警告机制提示迁移。在 index.tsx 中:
if (process.env.NODE_ENV !== 'production') { const warning = devUseWarning('Mentions'); warning.deprecated(!children, 'Mentions.Option', 'options'); }即生产环境下无感知,开发环境下控制台会打印[antd: Mentions]Mentions.Optionis deprecated. Please useoptionsinstead.的警告。对应测试用例位于tests/index.test.tsx:
it('warning if use Mentions.Option', () => { // 断言输出上述废弃警告 });数据驱动写法的另一优势是便于与异步数据源结合。参考 async.tsx demo:先在onSearch中发起请求,再通过options映射接口返回的数据,同时配合loading属性展示加载状态。
三、触发前缀 prefix、分隔符 split 与 getMentions 静态方法
Mentions 的默认触发前缀是@,但可以通过prefix配置为单个字符串或字符串数组,例如同时支持@提及人与#提及话题,见 prefix.tsx demo:
const MOCK_DATA = { '@': ['afc163', 'zombiej', 'yesmeck'], '#': ['1.0', '2.0', '3.0'], }; const App: React.FC = () => { const [prefix, setPrefix] = useState('@'); const onSearch: MentionsProps['onSearch'] = (_, newPrefix) => { setPrefix(newPrefix); }; return ( <Mentions placeholder="input @ to mention people, # to mention tag" prefix={['@', '#']} onSearch={onSearch} options={(MOCK_DATA[prefix] || []).map((value) => ({ key: value, value, label: value, }))} /> ); };这里的onSearch回调签名为(text: string, prefix: string) => void,第二个参数正是当前命中的前缀,据此可以动态切换候选数据源。与之配套的split属性用于设置选中项前后的分隔符,默认值为空格。
组件还暴露了一个静态工具方法Mentions.getMentions(value, config),用于从一段文本中解析出所有提及实体。其实现位于 index.tsx 末尾:
Mentions.getMentions = (value = '', config: MentionsConfig = {}): MentionsEntity[] => { const { prefix = '@', split = ' ' } = config; const prefixList: string[] = Array.isArray(prefix) ? prefix : [prefix]; return value .split(split) .map((str = '') => { let hitPrefix: string | null = null; prefixList.some((prefixStr) => { const startStr = str.slice(0, prefixStr.length); if (startStr === prefixStr) { hitPrefix = prefixStr; return true; } return false; }); if (hitPrefix !== null) { return { prefix: hitPrefix, value: str.slice(hitPrefix.length) }; } return null; }) .filter((entity) => !!entity && !!entity.value); };其解析逻辑可以概括为三步:按split分隔文本 → 对每个片段匹配前缀 → 返回{ prefix, value }实体(无前缀或值为空的片段被过滤)。测试用例验证了多前缀场景:
const mentions = getMentions('@light #bamboo cat', { prefix: ['@', '#'] }); // 返回 [{ prefix: '@', value: 'light' }, { prefix: '#', value: 'bamboo' }]这一方法在提交前校验「是否提到了足够多的人」等场景中非常实用,例如 form.tsx demo 中用它实现自定义校验:
const checkMention = async (_: any, value: string) => { const mentions = getMentions(value); if (mentions.length < 2) { throw new Error('More than one must be selected!'); } };四、事件回调体系与受控/非受控用法
Mentions 的事件体系围绕输入全流程设计,各回调的触发时机与参数如下表(摘自 组件 API 文档):
| 回调 | 触发时机 | 参数 |
|---|---|---|
| onChange | 值改变时 | (text: string) |
| onSelect | 选中选项时 | (option: OptionProps, prefix: string) |
| onSearch | 触发前缀命中(搜索)时 | (text: string, prefix: string) |
| onFocus | 获得焦点时 | () |
| onBlur | 失去焦点时 | () |
| onClear | 点击清除按钮时(5.20.0+) | () |
| onResize | 文本域尺寸变化时 | ({ width, height }) |
在值的管理上,Mentions 同时支持非受控(defaultValue)与受控(value+onChange)两种模式。受控模式配合清除能力的使用方式见 allowClear.tsx demo:
const [value, setValue] = useState('hello world'); <Mentions value={value} onChange={setValue} allowClear /> <Mentions value={value} onChange={setValue} allowClear={{ clearIcon: <CloseSquareFilled /> }} /> <Mentions value={value} onChange={setValue} allowClear rows={3} />allowClear自 5.13.0 起支持两种形态:布尔值true(使用默认清除图标)或对象{ clearIcon: <ReactNode> }(自定义清除图标)。在源码中它经由getAllowClear工具处理:const mergedAllowClear = getAllowClear(allowClear);。
五、与 Form 的深度集成
Mentions 与 Form 组件天然集成,可以直接作为Form.Item的表单控件使用。完整示例见 form.tsx demo,其关键点包括:
<Form form={form} onFinish={onFinish}> <Form.Item name="coders" label="Top coders" rules={[{ validator: checkMention }]} > <Mentions rows={1} options={mentionOptions} /> </Form.Item> ... </Form>- 校验规则:利用
getMentions在 validator 中检查提及数量,满足「必须选择多于一个」的业务约束; - 提交与重置:
form.validateFields()触发校验、form.resetFields()重置表单,均在onFinish中统一处理; - 上下文状态继承:从 index.tsx 可以看到,组件通过
React.useContext(FormItemInputContext)自动继承 Form 的校验状态与反馈图标,通过getMergedStatus合并上下文状态与自定义status,因此无需额外配置即可展示 error/warning 样式,并能渲染hasFeedback反馈图标(实现于源码中的suffixNode)。
六、更多的形态控制:只读、位置、状态与变体
围绕基本使用,仓库还提供了若干可直接借鉴的形态控制 demo:
只读与禁用(readonly.tsx):通过disabled禁用整个组件,或readOnly保持可聚焦但不可编辑,两者适用于不同交互语义。
展开方向(placement.tsx demo):默认建议面板向bottom展开,当输入框位于页面底部时,可通过placement="top"改为向上展开,避免面板超出视口。
校验状态与形态变体:status支持'error' | 'warning'(文档同时列出success/validating),用于在脱离 Form 的场景下手动标记校验状态;variant(5.13.0+)支持outlined(默认)、filled、borderless三种形态。源码中通过useVariant('mentions', customVariant)解析形态,并依据上下文状态生成对应的状态样式类名。
七、从源码看 Mentions 的封装结构
Mentions 在 Ant Design 中是围绕rc-mentions的封装层,核心职责包括(见 index.tsx):
- 主题与样式:
getPrefixCls('mentions', customizePrefixCls)生成前缀类名,useStyle注入 CSS-in-JS 样式与 hashId,并支持wrapCSSVar包裹 CSS 变量; - 空态兜底:未命中任何选项时,
notFoundContent默认渲染renderEmpty?.('Select')(可通过 ConfigProvider 全局定制),对应DefaultRenderEmpty; - 加载态:
loading为 true 时强制以Spin占位并禁用过滤(filterOption被替换为恒返回 true 的loadingFilterOption),同时silent传入底层避免触发搜索; - 扩展能力:
Mentions.Option静态子组件、_InternalPanelDoNotUseOrYouWillBeFired调试面板(由genPurePanel生成)、getMentions静态方法共同构成复合组件形态。
测试方面,tests/index.test.tsx 覆盖了getMentions解析、loading渲染、notFoundContent、allowClear(含自定义clearIcon)、Mentions.Option废弃警告、focus/blur 事件等关键行为,可作为你验证自定义改造时的参考依据。
结语
从一行basic.md出发,Mentions 组件实际上承载了数据驱动选项、多前缀触发、文本解析工具、Form 校验联动与多形态控制等完整能力。本文所有代码均可从仓库中的 demo 目录 直接找到可运行版本,组件完整 API 参数表请参阅 index.zh-CN.md 与 index.en-US.md,深入实现可阅读 index.tsx。
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考