ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

react-admin 树形管理实战:使用 `<TreeWithDetails>` 构建目录/分类同页编辑界面

react-admin 树形管理实战:使用 `<TreeWithDetails>` 构建目录/分类同页编辑界面 react-admin 树形管理实战使用TreeWithDetails构建目录/分类同页编辑界面【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-adminTreeWithDetails是 react-admin Enterprise Edition 生态中react-admin/ra-tree包提供的树形列表组件用于替代标准List来管理目录、分类等天然具有树结构的记录的浏览、编辑与拖拽重排。本文以官方文档为基础结合同仓库的Tree.md、TreeInput.md、Resource.md等文档系统讲解其 Props、视图组合方式与常见实战配置帮助你在 react-admin 中快速落地树 详情/编辑同页的管理界面。一、组件定位与适用场景在标准 react-admin 中List以表格形式平铺展示记录。但当数据是树结构如商品分类、目录、组织结构、权限树时扁平表格既难以表达层级也不便于就地编辑。TreeWithDetails正是为这类场景设计的替代品在同一页面中同时渲染树形结构和选中节点的 show 视图 / 编辑表单允许用户浏览树、编辑节点、创建子节点并通过拖拽重排整棵树。从源码结构看该组件属于 Enterprise Edition企业版扩展包react-admin/ra-tree底层基于 rc-tree 的Tree实现并通过 react-admin 的dataProvider与后端交互。使用时需要先安装并配置支持树操作的数据提供器dataProvider 需提供树查询与节点增删改能力例如dataProvider.addChildNode()。二、快速上手从List切换到TreeWithDetailsTreeWithDetails的使用方式与List高度相似核心差异在于列表视图组件改用TreeWithDetails创建视图使用CreateNode替代标准Create编辑视图使用EditNode替代标准Edit且表单必须搭配EditNodeToolbar工具栏。官方文档给出一个完整的分类管理示例// in src/category.js import { Admin, Resource, Create, Edit, SimpleForm, TextInput, } from react-admin; import { CreateNode, EditNode, EditNodeToolbar, TreeWithDetails, } from react-admin/ra-tree; // a Create view for a tree uses CreateNode instead of the standard Create const CategoriesCreate () ( CreateNode SimpleForm TextInput sourcename / /SimpleForm /CreateNode ); // an Edit view for a tree uses EditNode instead of the standard Edit const CategoriesEdit () ( EditNode SimpleForm toolbar{EditNodeToolbar /} TextInput sourcetitle / /SimpleForm /EditNode ); // a List view for a tree uses TreeWithDetails export const CategoriesList () ( TreeWithDetails create{CategoriesCreate} edit{CategoriesEdit} / ); // in src/App.js import { CategoriesList } from ./category; const App () ( Admin dataProvider{dataProvider} Resource list{CategoriesList} / /Admin );最小可运行配置只需两条在Admin中正常声明Resource并把list指向CategoriesList即可。树的渲染数据来源于 dataProvider 返回的树数据格式——即包含children字段的节点数组格式详见Tree.md例如{ id: 1, name: Clothing, children: [2, 6] }。三、Props 总览TreeWithDetails的完整 Props 如下表所示另接受Tree的全部 PropsPropRequiredTypeDefaultDescriptionaddRootButtonOptionalReactNode或false-用于添加根节点的创建按钮allowMultipleRootsOptionalbooleanfalse是否允许树存在多个根节点createOptionalReactNode-资源的创建表单draggableOptionalbooleanfalse是否允许用户拖拽重排节点editOptionalReactNode-资源的编辑表单filterOptionalobject-永久过滤条件hideRootNodesOptionalbooleanfalse是否隐藏所有根节点lazyOptionalbooleanfalse是否仅在节点展开时才加载其子节点motionOptionalbooleanfalse是否启用 rc-treeTree的展开/折叠过渡动画mutationModeOptionalstringundoable拖拽操作使用的mutationModeundoable、optimistic或pessimisticnodeActionsOptionalReactNode-自定义每个节点悬停时的下拉操作菜单showOptionalReactNode-资源的 show 视图showLineOptionalbooleanfalse是否显示节点连接线sxOptionalSxProps-Material UI 的sx快捷样式titleOptionalstring-显示在AppBar中的页面标题titleFieldOptionalstring-指定树中节点展示所用记录字段下文将按功能类别逐一深入说明每个 Props 的实战用法。四、create/edit/show三类视图的组合如果你希望同时开放创建、编辑和详情查看能力可以将三者同时传入import { EditButton, Labeled, SimpleForm, TextField, TextInput, TopToolbar, } from react-admin; import { AddChildButton, CreateNode, EditNode, EditNodeToolbar, ShowNode, TreeWithDetails, } from react-admin/ra-tree; const NodeShowAction () ( TopToolbar EditButton / AddChildButton / /TopToolbar ); const CategoriesShow () ( ShowNode actions{NodeShowAction /} SimpleForm Labeled labelId TextField sourceid / /Labeled Labeled labelTitle TextField sourcetitle / /Labeled /SimpleForm /ShowNode ); const CategoriesEdit () ( EditNode SimpleForm toolbar{EditNodeToolbar /} TextField sourceid labelid / TextInput sourcetitle / /SimpleForm /EditNode ); const CategoriesCreate () ( CreateNode SimpleForm TextInput sourcetitle / /SimpleForm /CreateNode ); export const CategoriesList () ( TreeWithDetails linkToshow show{CategoriesShow} edit{CategoriesEdit} create{CategoriesCreate} / );必须使用EditNodeToolbar的注意事项IMPORTANT在编辑视图中SimpleForm必须搭配EditNodeToolbar。该工具栏将 react-admin 默认的DeleteButton替换为 ra-tree 版本——后者删除的是整棵分支branch而不是单条记录。因此当你自定义Toolbar并需要包含删除按钮时必须从react-admin/ra-tree导入替代按钮import { Toolbar, ToolbarProps } from react-admin; import { DeleteBranchButton } from react-admin/ra-tree; import MyCustomButton from ./MyCustomButton; export const MyToolbar (props: ToolbarProps) ( Toolbar MyCustomButton / DeleteBranchButton / /Toolbar );覆盖节点创建/编辑的 mutationOptionsCreateNode与EditNode都接受mutationOptionsprop可用于覆写主 mutation 查询的配置例如onSuccess/onError回调或随请求透传给 dataProvider 的meta对象const CategoriesCreate () ( CreateNode mutationOptions{{ onSuccess: () { console.log(Success!); }, onError: () { console.log(Error); }, meta: { foo: bar }, // The meta object will be passed to the dataProvider methods }} SimpleForm TextInput sourcename / /SimpleForm /CreateNode );五、多根树支持allowMultipleRoots与addRootButton默认情况下ra-tree 一棵树只允许一个根节点。当业务上需要多个根如多级分类并列展示时设置allowMultipleRootsexport const CategoriesList (props: ListProps) ( TreeWithDetails create{CategoriesCreate} edit{CategoriesEdit} allowMultipleRoots {...props} / );当allowMultipleRoots为true、或当前树中没有任何根节点时组件会显示一个添加根节点按钮。你可以用addRootButton传入自定义按钮// in src/posts.js import { CreateButton } from react-admin; export const CategoriesList () ( TreeWithDetails allowMultipleRoots addRootButton{CreateButton labelAdd Categories! /} ... /TreeWithDetails );Tip向addRootButton传入false可以完全隐藏该按钮。六、拖拽重排draggable与mutationMode允许用户通过拖拽重排节点只需添加draggablepropexport const CategoriesList () TreeWithDetails draggable /;mutationMode决定拖拽操作采用哪种提交策略默认undoable可选值与标准 react-adminEdit的三种 mutation 模式一致详见Edit.mdpessimistic先调用 dataProvider成功后才在本地应用变更并执行副作用optimistic立即在本地应用变更并执行副作用再调用 dataProvider失败则刷新页面并报错undoable默认立即在本地应用变更弹出含撤销按钮的通知用户撤销则不发请求否则约 5 秒后提交给 dataProvider。TreeWithDetails mutationModepessimistic /Note使用undoable默认或pessimistic模式时拖拽操作后、mutation 真正完成即 dataProvider 被调用并返回之前节点数据可能是过期的。原因在于react-admin 虽然可以乐观地重排节点顺序但无法根据你的具体实现对节点数据本身应用所需的变更。因此依赖节点数据内容渲染的 UI 可能出现短暂不一致。拖拽产生的变更最终会通过 dataProvider 的节点移动相关方法例如移动节点、调整子级归属等持久化请确保你的数据提供器实现了对应的树操作。七、永久过滤子集filter如果只想展示整棵树的某个子树可以使用filterprop 进行永久过滤。例如employees资源带有department字段只想展示 Finance 部门的树const EmployeeList () TreeWithDetails filter{{ department: finance }} /;Notefilter仅在过滤字段能提取出带独立根节点的子树时才有效。如果用它过滤出零散的节点子集例如只显示male员工树中的拖拽行为将不会按预期工作。八、隐藏根节点hideRootNodes有些树出于技术原因只有一个根节点用户不应该看到它。此时可用hideRootNodes隐藏所有根节点export const CategoriesList () TreeWithDetails hideRootNodes /;九、懒加载lazy当树的节点数量很大时可只在初始阶段加载根节点、展开某个节点时再加载其子节点。启用方式为设置lazyexport const CategoriesList () TreeWithDetails lazy /;Important使用lazy模式时不能使用undoablemutation 模式。必须在EditNode上将mutationMode设置为pessimistic或optimistic。一个完整的懒加载示例注意编辑视图的 mutationMode 配置import React from react; import { Admin, Resource, SimpleForm, TextField, TextInput } from react-admin; import { EditNode, EditNodeToolbar, TreeWithDetails } from react-admin/ra-tree; import CategoriesCreate from ../CategoriesCreate; import i18nProvider from ../i18nProvider; import dataProvider from ./dataProvider; const CategoriesEdit () ( EditNode mutationModepessimistic SimpleForm toolbar{EditNodeToolbar /} TextField sourceid / TextInput sourcename / /SimpleForm /EditNode ); const CategoriesList () ( TreeWithDetails titleFieldname edit{CategoriesEdit} create{CategoriesCreate} lazy / ); export const App () ( Admin dataProvider{dataProvider} i18nProvider{i18nProvider} Resource namecategories list{CategoriesList} / /Admin );官方文档中的懒加载演示视频docs/img/ra-tree-lazy.webm/ra-tree-lazy.mp4直观展示了展开时按需加载子节点的效果首屏只请求根节点点击展开某节点时才发起对应子节点的请求。十、展开/折叠过渡动画motionrc-tree 的Tree本身支持自定义节点展开/折叠的过渡动画但 ra-tree默认禁用了这些动画——它们已知会与点击展开expand on click功能产生冲突。需要时可通过motionprop 启用export const CategoriesList () TreeWithDetails motion /;motion也可以传入一个过渡配置对象完全自定义动画细节import { TreeWithDetails } from react-admin/ra-tree; import { CSSProperties } from react; const myMotion { motionName: node-motion, motionAppear: false, onAppearStart: (): CSSProperties ({ height: 0, width: 0 }), onAppearActive: (node: HTMLElement): CSSProperties ({ height: node.scrollHeight, width: node.scrollWidth, }), onLeaveStart: (node: HTMLElement): CSSProperties ({ height: node.offsetHeight, width: node.scrollWidth, }), onLeaveActive: (): CSSProperties ({ height: 0, width: 0 }), }; export const CategoriesList () ( TreeWithDetails motion{myMotion} sx{{ .node-motion: { transition: all .7s, overflowX: hidden, overflowY: hidden, }, }} / );其中motionName用于指定 CSS 类名配合sx中的transition、overflow样式即可实现节点高度的平滑伸缩效果。十一、自定义节点操作菜单nodeActions默认情况下每个节点在悬停时会显示一个操作下拉菜单菜单默认只包含一个删除动作。通过nodeActions可以定制该菜单import { NodeActions, DeleteMenuItem, TreeWithDetails, } from react-admin/ra-tree; const MyCustomActionMenuItem forwardRef( ({ record, resource, parentId }, ref) { const handleClick () { // Do something with dataProvider ? }; return ( MenuItem ref{ref} onClick{handleClick} Do something /MenuItem ); } ); const MyActions (props: NodeActionsProps) ( NodeActions {...props} MyCustomActionMenuItem / DeleteMenuItem / /NodeActions ); const CategoriesList () ( TreeWithDetails titleFieldname edit{CategoriesEdit} draggable showLine nodeActions{MyActions /} / );自定义菜单项如上面的MyCustomActionMenuItem会接收到当前记录record、资源名resource与父节点 idparentId方便你基于这些上下文实现针对当前节点的操作。十二、节点连接线showLinera-tree 默认采用 react-admin 的样式通过缩进与箭头表达层级。设置showLine为true后将保留 rc-tree 原生的层级图标并以连接线勾勒父子关系export const CategoriesList () TreeWithDetails showLine /;十三、页面标题与节点标题title与titleFieldtitle树视图默认标题为[资源名] list例如 Posts list。用title自定义// in src/posts.js export const CategoriesList () ( TreeWithDetails titleList of categories.../TreeWithDetails );title既可以是字符串也可以是你自定义的 React 元素。titleField树中每个节点默认使用资源的recordRepresentation作为标题。recordRepresentation未设置时react-admin 会按name→title→label→reference→id的顺序选取可用字段。如需显式指定节点标题字段使用titleField// in src/posts.js export const CategoriesList () ( TreeWithDetails titleFieldname.../TreeWithDetails );十四、在表单中选择节点搭配TreeInput如果你的业务需要在表单中让用户选择树中的节点例如给商品设置所属分类请使用 ra-tree 的TreeInput组件而不是TreeWithDetailsimport { Edit, SimpleForm, TextInput } from react-admin; import { TreeInput } from react-admin/ra-tree; export const ProductEdit () ( Edit SimpleForm TextInput sourceid disabled / TextInput sourcename / TreeInput sourcecategory data{[ { id: 1, title: Clothing, isRoot: true, children: [2, 6] }, { id: 2, title: Men, children: [3] }, { id: 3, title: Suits, children: [4, 5] }, { id: 4, title: Slacks, children: [] }, { id: 5, title: Jackets, children: [] }, { id: 6, title: Women, children: [7, 10, 11] }, { id: 7, title: Dresses, children: [8, 9] }, { id: 8, title: Evening Gowns, children: [] }, { id: 9, title: Sun Dresses, children: [] }, { id: 10, title: Skirts, children: [] }, { id: 11, title: Blouses, children: [] }, ]} / /SimpleForm /Edit );TreeInput底层同样基于 rc-tree数据格式与dataProvider.getTree()的返回格式一致含children字段的节点数组。它支持multiple多选、hideRootNodes、titleField、checkStrictly等配置若需要通过引用资源自动拉取树数据可搭配ReferenceNodeInput使用。两者分工明确TreeWithDetails负责管理整棵树TreeInput负责在表单中挑选节点。十五、控制子节点插入位置insertAsFirstChild默认情况下用户为某节点新增子节点时新节点会被插入为父节点的最后一个子节点。如需强制插入为第一个子节点在AddChildButton上设置insertAsFirstChild// in src/posts.js import { TopToolbar } from react-admin; import { AddChildButton, EditNode, TreeWithDetails, } from react-admin/ra-tree; const NodeEditActions () ( TopToolbar AddChildButton labelAdd child at top insertAsFirstChild / /TopToolbar ); const CategoriesEdit () ( EditNode actions{NodeEditActions /}.../EditNode ); export const CategoriesList () ( TreeWithDetails edit{CategoriesEdit}.../TreeWithDetails );Note该特性要求dataProvider.addChildNode()支持position参数请确认你的数据提供器实现已涵盖此能力。十六、小结TreeWithDetails将 react-admin 的列表、创建、编辑、show 视图整合进一棵可交互的树中覆盖了树形资源管理的完整闭环浏览展开/折叠、懒加载、子树过滤→ 编辑同页表单、分支删除→ 组织拖拽重排、多根、插入位置控制→ 引用表单内TreeInput选节点。核心配置要点可归纳为创建/编辑视图分别用CreateNode、EditNode编辑表单务必搭配EditNodeToolbar删除分支而非单条记录拖拽重排开启draggable并根据数据一致性要求选择mutationMode大节点量场景开启lazy懒加载同时将EditNode的mutationMode调整为optimistic或pessimistic节点标题由titleField控制页面标题由title控制样式统一走sx涉及表单选节点时切换到TreeInput或ReferenceNodeInput。如需进一步了解树数据格式、Tree的展开/选中/拖拽事件回调onExpand、onSelect、onDrop等以及dataprop 的详细说明可继续阅读仓库中的Tree.md与TreeInput.md。【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表