资讯动态

react-admin `<TabbedShowLayout>` 深度指南:Show 视图 Tab 分组布局的配置、源码与权限控制

发布时间:2026/9/21 2:41:38 来源:尧图企业网站定制
前端UI组件【免费下载链接】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点击查看免费下载TabbedShowLayout是 react-admin 中用于 Show详情视图的布局组件它将一条记录的多个字段按 Tab 分组展示每个 Tab 内以单列Material UIStack形式渲染字段。本文基于仓库文档与源码完整讲解它的 Props、TabbedShowLayout.Tab子组件、URL 同步机制、自定义 Tabs、样式覆盖与 RBAC 权限控制并结合ra-ui-materialui包中的真实实现与测试用例说明底层原理帮助你写出可复制、可维护的 Tab 化详情页。一、组件定位与核心概念TabbedShowLayout渲染一组Tabs每个 Tab 内通过 Material UI 的Stack组件以单列布局展示记录字段源码定义。它的核心工作方式字段渲染委托给子元素子元素必须是TabbedShowLayout.Tab组件自动加标签TabbedShowLayout.Tab会将每个字段包装进Labeled组件以显示字段标签URL 同步切换 Tab 会更新当前 URL默认使用 Tab 的索引作为路径第一个 Tab 显示在根路径可通过每个 Tab 的path属性自定义路径若希望第一个 Tab 作为首页则省略path。从源码看TabbedShowLayout从RecordContext读取记录并使用OptionalRecordContextProvider包裹自身TabbedShowLayout.tsx这决定了它可以嵌套在Show下使用也可以通过record属性脱离 Context 独立渲染。二、基本用法Usage将TabbedShowLayout用作Show组件或任何创建RecordContext的组件的后代通过TabbedShowLayout.Tab定义 Tab再在 Tab 内放置需要展示的字段import { Show, TabbedShowLayout } from react-admin export const PostShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelsummary TextField labelId sourceid / TextField sourcetitle / TextField sourceteaser / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelbody pathbody RichTextField sourcebody label{false} / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelMiscellaneous pathmiscellaneous TextField labelPassword (if protected post) sourcepassword typepassword / DateField labelPublication date sourcepublished_at / NumberField sourceaverage_note / BooleanField labelAllow comments? sourcecommentable defaultValue / TextField labelNb views sourceviews / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelcomments pathcomments ReferenceManyField referencecomments targetpost_id label{false} DataTable DataTable.Col sourcebody / DataTable.Col sourcecreated_at field{DateField} / DataTable.Col EditButton / /DataTable.Col /DataTable /ReferenceManyField /TabbedShowLayout.Tab /TabbedShowLayout /Show );在这个示例中summaryTab 不带path因此它在根路径如/posts/123/show展示其余 Tab 分别对应/body、/miscellaneous、/comments子路径。三、Props 一览TabbedShowLayout接受以下 PropsTabbedShowLayoutProps 定义PropRequiredTypeDefaultDescriptionchildrenRequiredReactNode渲染记录字段的组件须为TabbedShowLayout.TabclassNameOptionalstring应用到根元素上的 class 名dividerOptionalReactElement每个字段之间可选的分隔元素recordOptionalobject要渲染的记录传给RecordContextspacingOptionalnumber1字段之间的间距传给Stack组件sxOptionalobject覆盖应用到根元素的样式syncWithLocationOptionalbooleantrue设为false可禁用将活动 Tab 存到 URLtabsOptionalReactElement自定义的 Tabs 组件其余 Props 会被透传给根组件div。此外源码中syncWithLocation true的默认值直接体现在组件解构赋值处TabbedShowLayout.tsx#L93。四、children与TabbedShowLayout.TabTabbedShowLayout的子元素必须是TabbedShowLayout.Tab组件源码中通过TabbedShowLayout.Tab Tab静态挂载见 TabbedShowLayout.tsx#L194。该组件同时负责渲染 Tab 头部与活动 Tab 的内容既可通过 URL 管理切换也可用内部状态管理。TabbedShowLayout.Tab接受以下 PropsTabProps 定义label每个 Tab 显示的字符串必填icon显示在标签前的图标可选必须是组件path用于自定义 URL 的字符串可选countTab 内的条目数量显示在标签旁className应用到 Tab头部contentClassName应用到 Tab内容。// in src/posts.js import * as React from react; import FavoriteIcon from mui/icons-material/Favorite; import PersonPinIcon from mui/icons-material/PersonPin; import { Show, TabbedShowLayout, TextField } from react-admin; export const PostShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelContent icon{FavoriteIcon /} TextField sourcetitle / TextField sourcesubtitle / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelMetadata icon{PersonIcon /} pathmetadata TextField sourcecategory / /TabbedShowLayout.Tab /TabbedShowLayout /Show );从源码看count会以label (count)的格式拼在标签后面Tab.tsx#L103-L108Tab 内容渲染时Stack是根容器默认spacing 1同时会给每个字段打上ra-field、ra-field-{source}与RaTab-row的 classTab.tsx#L125-L146。五、divider字段之间的分隔线Stack支持可选的divider属性即在每行之间渲染一个组件。TabbedShowLayout同样接受该属性并将其透传给Stack。import { Divider } from mui/material; const PostShow () ( Show TabbedShowLayout divider{Divider flexItem /} TabbedShowLayout.Tab labelmain TextField sourcetitle / TextField sourcesubtitle / /TabbedShowLayout.Tab /TabbedShowLayout /Show );六、spacing控制字段间距TabbedShowLayout.Tab内部渲染的是 Material UI 的Stack可以通过spacing属性自定义每行之间的间距const PostShow () ( Show TabbedShowLayout spacing{2} TabbedShowLayout.Tab labelmain TextField sourcetitle / TextField sourcesubtitle / /TabbedShowLayout.Tab /TabbedShowLayout /Show );默认间距为1这一默认值同时体现在 Tab.tsx#L83 的spacing 1中。spacing的类型是ResponsiveStyleValuenumber | string因此它也支持响应式取值如{ xs: 1, md: 2 }。七、syncWithLocationTab 与 URL 同步默认情况下为了让用户能用浏览器后退按钮回到上一个 TabTabbedShowLayout会把活动 Tab 存到 location 中。如果希望同一页面存在多个TabbedShowLayout可以传syncWithLocation{false}关闭同步import { TabbedShowLayout, Tab } from react-admin export const PostShow () ( Show TabbedShowLayout syncWithLocation{false} TabbedShowLayout.Tab labelsummary TextField labelId sourceid / TextField sourcetitle / TextField sourceteaser / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelbody pathbody RichTextField sourcebody label{false} / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelMiscellaneous pathmiscellaneous TextField labelPassword (if protected post) sourcepassword typepassword / DateField labelPublication date sourcepublished_at / NumberField sourceaverage_note / BooleanField labelAllow comments? sourcecommentable defaultValue / TextField labelNb views sourceviews / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelcomments pathcomments ReferenceManyField referencecomments targetpost_id label{false} DataTable DataTable.Col sourcebody / DataTable.Col sourcecreated_at field{DateField} / DataTable.Col EditButton / /DataTable.Col /DataTable /ReferenceManyField /TabbedShowLayout.Tab /TabbedShowLayout /Show );注意当syncWithLocation为false时TabbedShowLayout.Tab的path属性会被忽略。源码揭示了两种模式的实现差异TabbedShowLayout.tsx#L130-L188同步模式渲染Routes/Route/Outlet每个 Tab 对应一个路由路径由getShowLayoutTabFullPath(tab, index)计算非同步模式组件内部维护useState(0)的tabValue点击 Tab 时通过handleTabChange更新内部状态并按索引匹配渲染对应 Tab 内容。// packages/ra-ui-materialui/src/detail/TabbedShowLayoutTabs.tsx export const getShowLayoutTabFullPath (tab, index) ${tab.props.path ? ${tab.props.path} : index 0 ? index : };这段路径计算逻辑说明第一个 Tabindex 0且未设置path时路径为空字符串即根 URL其余未设置path的 Tab 使用其索引号。测试用例should sync tabs with location by default与should sync tabs with location by default when using custom tab paths验证了点击 Tab2 后路径变为/1或/second、点击 Tab1 后回到/的行为TabbedShowLayout.spec.tsx#L51-L115。八、record脱离 RecordContext 渲染默认TabbedShowLayout从RecordContext读取记录。但通过传入record属性可以在没有RecordContext的环境下渲染const StaticPostShow () ( TabbedShowLayout record{{ id: 123, title: Hello world }} TabbedShowLayout.Tab labelmain TextField sourcetitle / /TabbedShowLayout.Tab /TabbedShowLayout );传入record后TabbedShowLayout会用它创建一个RecordContext源码中由OptionalRecordContextProvider实现TabbedShowLayout.tsx#L131。这正是受控模式Controlled Mode——即完全由外部给定记录数据、脱离数据获取上下文来渲染静态内容。九、tabs自定义 Tabs 组件默认情况下TabbedShowLayout使用 react-admin 内部组件TabbedShowLayoutTabs渲染 Tab 头部。你可以通过tabs属性传入自定义组件来覆盖默认行为。同时传给TabbedShowLayoutTabs的 props 会被透传给其内部的 Material UITabs组件因此你可以不复制 react-admin 源码就定制 Tabs。例如要实现可滚动的 Tabs把variantscrollable和scrollButtonsauto传给TabbedShowLayoutTabs再通过tabs属性接入import { Show, TabbedShowLayout, TabbedShowLayoutTabs, } from react-admin; const ScrollableTabbedShowLayout () ( Show TabbedShowLayout tabs{TabbedShowLayoutTabs variantscrollable scrollButtonsauto /} ... /TabbedShowLayout /Show ); export default ScrollableTabbedShowLayout;从源码看TabbedShowLayoutTabs渲染一个indicatorColorprimary的Tabs每个 Tab 头部通过context: header克隆渲染在同步模式下它通过useParams()读取 URL 中的*参数作为当前 Tab 值否则使用内部状态值TabbedShowLayoutTabs.tsx。十、TabbedShowLayout.Tab的 Labeled 包装机制TabbedShowLayout.Tab会把每个子元素包装在Labeled组件中见 Tab.tsx#L125-L146 的renderContent。Labeled默认使用字段的source经人类化humanize处理后的文本作为标签你可以通过给字段传label属性自定义标签const PostShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelmain TextField labelMy Custom Title sourcetitle / /TabbedShowLayout.Tab /TabbedShowLayout /Show );Labeled label默认使用人类化的source作为标签你也可以传入 i18n 翻译键来自定义可参考 Labeled 组件文档const PostShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelmain TextField labelMy Custom Title sourcetitle / TextField labelmy.custom.translationKey sourcedescription / /TabbedShowLayout.Tab /TabbedShowLayout /Show ); // translates to const PostShow () ( Show TabbedShowLayout Labeled labelMy Custom Title TextField sourcetitle / /Labeled Labeled labelmy.custom.translationKey TextField sourcedescription / /Labeled /TabbedShowLayout /Show );如果希望某个字段不带标签装饰给字段传label{false}即可const PostShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelmain TextField label{false} sourcetitle / /TabbedShowLayout.Tab /TabbedShowLayout /Show );TabbedShowLayout.Tab的子元素可以是任意组件你也可以传入自定义组件const PostTitle () { const record useRecordContext(); return spanPost {record.title}/span; }; const PostShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelmain PostTitle labeltitle / /TabbedShowLayout.Tab /TabbedShowLayout /Show );十一、sxCSS API 样式定制TabbedShowLayout接受常规的className属性借助sx属性你还可以覆盖 react-admin 注入到内部组件的众多 class 名语法与示例参见 sx 文档。该属性支持以下子类Rule nameDescription .RaTabbedShowLayout-content应用到内容区域Tabs 下方从源码看根元素是一个名为RaTabbedShowLayout的 styled 组件内容区默认有theme.spacing(1)上下、theme.spacing(2)左右的 paddingTabbedShowLayout.tsx#L211-L225。如果要用应用级样式覆盖application-wide style overrides定制所有TabbedShowLayout实例的样式使用RaTabbedShowLayout这一主题键详见 AppTheme 文档。此外TabbedShowLayout.Tab的className传给 Tab 头部、contentClassName传给 Tab 内容用于分别定制这两部分的样式。十二、Access Control基于 RBAC 的 Tab 级权限控制如果希望根据一组权限隐藏某些 Tab请使用react-admin/ra-rbac包中的TabbedShowLayout企业版 ra-rbac 模块-import { TabbedShowLayout } from react-admin; import { TabbedShowLayout } from react-admin/ra-rbac;与TabbedShowLayout.Tab配合使用并为 Tab 添加name属性来定义用户需要具备 read 权限的资源import { Show, TextField } from react-admin; import { TabbedShowLayout } from react-admin/ra-rbac; const authProvider { // ... canAccess: async ({ action, record, resource }) canAccessWithPermissions({ permissions: [ { action: [list, show], resource: products }, { action: read, resource: products.tab.description }, // { action: read, resource: products.tab.stock }, { action: read, resource: products.tab.images }, { action: read, resource: products.reference }, { action: read, resource: products.width }, { action: read, resource: products.height }, { action: read, resource: products.thumbnail }, ], action, record, resource, }), }; const ProductShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelDescription namedescription TextField sourcereference / TextField sourcewidth / TextField sourceheight / TextField sourcedescription / /TabbedShowLayout.Tab {/* This tab is not displayed for the user */} TabbedShowLayout.Tab labelStock namestock TextField sourcestock / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelImages nameimages TextField sourceimage / TextField sourcethumbnail / /TabbedShowLayout.Tab /TabbedShowLayout /Show );TabbedShowLayout.Tab还会只渲染用户具备 read 权限的子字段。例如下面这个 authProvider 中products.description与products.image权限缺失products.tab.stock也未授权因此对应 Tab 与字段都不会展示import { Show, TextField } from react-admin; import { TabbedShowLayout } from react-admin/ra-rbac; const authProvider { // ... canAccess: async ({ action, record, resource }) canAccessWithPermissions({ permissions: [ { action: [list, show], resource: products }, { action: read, resource: products.reference }, { action: read, resource: products.width }, { action: read, resource: products.height }, // products.description is missing { action: read, resource: products.thumbnail }, // products.image is missing { action: read, resource: products.tab.description }, // products.tab.stock is missing { action: read, resource: products.tab.images }, ], action, record, resource, }), }; const ProductShow () ( Show TabbedShowLayout TabbedShowLayout.Tab labelDescription namedescription TextField sourcereference / TextField sourcewidth / TextField sourceheight / {/* Field Description is not displayed */} TextField sourcedescription / /TabbedShowLayout.Tab {/* Tab Stock is not displayed */} TabbedShowLayout.Tab labelStock namestock TextField sourcestock / /TabbedShowLayout.Tab TabbedShowLayout.Tab labelImages nameimages {/* Field Image is not displayed */} TextField sourceimage / TextField sourcethumbnail / /TabbedShowLayout.Tab /TabbedShowLayout /Show );十三、源码原理剖析TabbedShowLayout 的工作流程结合ra-ui-materialui包源码可以还原完整的渲染链路TabbedShowLayout.tsx、Tab.tsx、TabbedShowLayoutTabs.tsx记录获取useRecordContext(props)从 Context 读取记录若record为空则直接返回null子元素清洗Children.toArray(children).filter(child child ! null)过滤掉null保证第一个有效 Tab能正确展示测试should display the first valid Tab component and its content覆盖了子元素中存在null的场景TabbedShowLayout.spec.tsx#L30-L49头部渲染cloneElement(tabs, { onChange, syncWithLocation, value }, children)克隆默认或自定义 Tabs 组件并注入切换回调TabbedShowLayoutTabs再为每个 Tab 克隆出context: header的头部头部在同步模式下以完整路径为value并用LinkBase包裹实现Tab 即链接内容渲染同步模式下每个 Tab 内容作为独立路由Route path{getShowLayoutTabFullPath(tab, index)}渲染Outlet /承载当前 Tab非同步模式下按内部tabValue匹配索引渲染内容装饰每个字段被Labeled包裹并带上ra-field、ra-field-{source}、RaTab-rowclass整体放入Stack spacing{spacing} divider{divider}。这一头部/内容双 context 克隆 路由驱动的设计是TabbedShowLayout既能同步 URL、又能支持syncWithLocation{false}内部状态模式的根本原因。十四、相关资源See AlsoField components字段组件总览ShowGuesser根据记录类型猜测字段的 Show 布局SimpleShowLayout不带 Tab 的更简单布局Labeled字段标签装饰组件sx 样式语法与示例AppTheme应用级组件样式覆盖组件实现与测试源码TabbedShowLayout.tsx、Tab.tsx、TabbedShowLayoutTabs.tsx、TabbedShowLayout.spec.tsx赞分享前端UI组件【免费下载链接】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点击查看免费下载相关推荐react-admin Show 组件完全指南从记录展示到权限控制与实时更新react admin Show 组件完全指南从记录展示到权限控制与实时更新 Show 是 react admin 中用于展示单条记录详情的核心页面组件。前端UI组件react-admin SimpleShowLayout 完全指南从单列详情布局到多列网格与权限控制react admin SimpleShowLayout 完全指南从单列详情布局到多列网格与权限控制 SimpleShowLayout 是 react a前端UI组件IdentityServer4.Admin项目配置指南身份管理与权限控制IdentityServer4.Admin项目配置指南身份管理与权限控制 项目概述 IdentityServer4.Admin是一个基于IdentitySer上一篇gdsfactory社区支持如何获取帮助并参与开源硬件革命下一篇Pinpoint用户认证系统LDAP集成配置教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价