ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ant-design Tag 数据驱动动态标签:用数组生成与管理可关闭标签的完整实践

ant-design Tag 数据驱动动态标签:用数组生成与管理可关闭标签的完整实践 ant-design Tag 数据驱动动态标签用数组生成与管理可关闭标签的完整实践【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/antde/ant-design导读本文以 ant-design 仓库中的 Tag 组件演示文档 components/tag/demo/control.md 为核心讲解如何用数组State 数据驱动生成一组标签并实现点击关闭即从数据源移除、点击按钮即追加新标签的完整增删交互。文章将完整继承原文档的示例代码并深入到 Tag 组件源码 与 标签样式 中剖析afterClose与onClose的差异、关闭动画的底层触发链路帮助你掌握在真实业务场景如关键词管理、筛选条件集合中安全地动态管理标签。一、场景与需求为什么需要数据生成标签在 ant-design 的 Tag 组件文档 中Tag 被定义为进行标记和分类的小标签。但静态写死的标签见 basic.md只能展示无法满足以下真实业务诉求关键词管理用户为内容打上多个标签并可随时删除不再需要的标签筛选条件集合动态添加多个筛选标签删掉某个条件后条件列表随之收缩增量追加通过输入或按钮持续追加新标签且每个新标签都可独立关闭。解决这类问题的标准做法正是原文档control.md所演示的把标签集合放进组件的 State数组渲染时map成一组Tag删除时从数组中filter掉对应项追加时向数组push新项。数据是唯一事实来源Single Source of Truth界面只是数据的投影。二、核心代码用数组驱动标签的增删原文档完整示例原文档 components/tag/demo/control.md 提供了完整的可运行示例这里完整继承并补充注释说明import { Tag, Button } from antd; let index 2; // 全局计数器保证新增标签的 key 不重复 const App React.createClass({ // 初始数据两个标签每个标签是一个包含 key 与 name 的对象 getInitialState() { return { tags: [ { key: 1, name: 标签一 }, { key: 2, name: 标签二 }, ], }; }, // 关闭根据 key 过滤掉被删除的标签生成新数组并 setState handleClose(key) { const tags [...this.state.tags].filter(tag (tag.key ! key) tag); console.log(tags); this.setState({ tags }); }, // 追加复制数组push 一个新标签对象 addTag() { const tags [...this.state.tags]; index 1; tags.push({ key: index, name: 新标签${index} }); this.setState({ tags }); }, render() { return ( div {this.state.tags.map(tag Tag key{tag.key} closable afterClose{this.handleClose.bind(this, tag.key)}{tag.name}/Tag )} div Button onClick{this.addTag}添加标签/Button /div /div ); } }); ReactDOM.render(App /, mountNode);原文档的关键提示afterClose而不是onClose原文档特别强调了一句话这也是本示例最核心的技术要点使用afterClose而不是onClose删除时有动画效果。原因在于onClose在用户点击关闭图标的那一刻立即触发此时组件尚未播放退场动画如果立刻从数组中移除该标签React 会直接卸载节点动画根本没有机会执行。而afterClose会等到缩带动画完整播放结束之后才触发此时再更新数组、移除标签界面便呈现出平滑的收起消失效果。数组操作的两个易错点追加时先复制再pushaddTag中先执行const tags [...this.state.tags]创建新数组再push新对象最后setState({ tags })。直接push原数组会修改 State 引用违反 React 不可变更新原则可能导致渲染优化失效。删除时用filter生成新数组handleClose中filter(tag tag.key ! key)同样返回全新数组配合key精确定位要移除的标签避免误删。三、源码级原理afterClose背后的动画触发链路要真正理解为什么用afterClose需要走进 Tag 组件的实现。查看 components/tag/index.jsx 源码可以还原完整调用链close(e) { const dom ReactDOM.findDOMNode(this); dom.style.width ${dom.offsetWidth}px; // 锁定当前宽度执行两次保证布局稳定 dom.style.width ${dom.offsetWidth}px; this.setState({ closing: true }); this.props.onClose(e); // ① 此刻立即触发 onClose } animationEnd(key, existed) { if (!existed !this.state.closed) { this.setState({ closed: true, closing: false }); this.props.afterClose(); // ② 动画结束后才触发 afterClose } }从源码结构看关闭流程分两阶段阶段一点击close()先把 DOM 节点的width锁定为当前宽度再将closing置为true并立即调用this.props.onClose(e)。样式表中 tag.less 对.ant-tag-close定义了width: 0 !important; padding: 0; margin: 0;配合rc-animate的ant-tag-zoom过渡类antZoomOut动画时长0.2s完成横向收起动画。阶段二动画结束rc-animate的onEnd回调触发animationEnd(key, existed)当existed为false节点即将卸载且尚未标记关闭时置closed: true并调用this.props.afterClose()。此时 DOM 已不可见从数据数组移除标签才不会出现闪烁/瞬间消失。因此onClose适合做确认/记录等即时逻辑afterClose才适合做从数据源移除这类会触发重渲染的操作——这正是原文档提示的本质。四、组件 API 与参数语义对照官方文档配合 components/tag/index.md 的 API 表本示例涉及的关键参数如下参数说明类型可选值默认值closable标签是否可以关闭boolean—falseonClose关闭时的回调点击立即触发function—无afterClose动画关闭后的回调动画结束触发function—无color标签的色彩stringbluegreenyellowred无closable默认关闭动态标签必须显式加上closable才会渲染右上角叉号。源码 tag/index.jsx 中AntTag.defaultProps确认了默认值closable: false、onClose() {}、afterClose() {}。四个颜色值在样式表 style/components/tag.less 中各有对应背景link-color、success-color、warning-color、error-color可在 colorful.md 看到四种颜色与closable组合的效果。若要为动态标签增加视觉区分只需给Tag colorblue等传参即可。五、实战扩展将示例落地为生产可用的组件原文档示例使用React.createClass与getInitialState这是 React 早期ES5写法。在需要实际复用时可以按当前 React 生态改造成函数组件 Hooks 形式业务逻辑与原示例完全一致import React, { useState, useRef } from react; import { Tag, Button } from antd; const TagGroup () { const [tags, setTags] useState([ { key: 1, name: 标签一 }, { key: 2, name: 标签二 }, ]); const indexRef useRef(2); // 替代全局变量 index避免命名冲突 const handleClose (key) { setTags(tags tags.filter(tag tag.key ! key)); }; const addTag () { indexRef.current 1; setTags(tags [...tags, { key: indexRef.current, name: 新标签${indexRef.current} }]); }; return ( div {tags.map(tag Tag key{tag.key} closable afterClose{handleClose.bind(null, tag.key)} {tag.name} /Tag )} div Button onClick{addTag}添加标签/Button /div /div ); }; export default TagGroup;改造要点key必须稳定且唯一示例用自增的index作key。若用name作 key会出现两个同名标签冲突、以及重名时filter误删的问题自增计数器原示例的全局let index或 Hooks 中的useRef能保证每次追加的key唯一。回调需绑定具体参数afterClose{this.handleClose.bind(this, tag.key)}将每个标签的key预先绑定进回调map渲染时无需再为每个标签创建内联匿名函数包裹层语义清晰且避免闭包捕获过期状态。console.log(tags)可移除原示例仅用于演示数组内容生产代码中删除即可。在此基础上还可以继续扩展将handleClose内改为调用服务端接口删除持久化标签把添加标签的按钮替换为 Input 输入框 回车提交或在addTag中加入去重与数量上限校验。六、小结围绕 components/tag/demo/control.md本文完整继承并扩展了数据生成标签的实践方案用State 数组 map渲染实现标签集合的数据驱动用filter生成新数组删除标签、push新对象追加标签遵循不可变更新原则牢记afterClose而非onClose这是删除动画能否生效的关键底层由 tag/index.jsx 的两阶段关闭链路与 tag.less 的ant-tag-zoom动画共同支撑结合 Tag API 表 正确使用closable、onClose、afterClose、color四个参数并可将示例迁移为函数组件形态落地到真实业务。【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/antde/ant-design创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表