news 2026/9/19 4:04:11

用 ConfigProvider 主题 Token 在 antd 中还原 V4 风格 Menu:menu-v4 示例深度拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 ConfigProvider 主题 Token 在 antd 中还原 V4 风格 Menu:menu-v4 示例深度拆解

用 ConfigProvider 主题 Token 在 antd 中还原 V4 风格 Menu:menu-v4 示例深度拆解

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design

Ant Design 从 v5 起全面切换到 CSS-in-JS 的 Design Token 体系,Menu 组件的视觉细节也随之调整。对于希望沿用 v4 时代"方角、无内边距、左侧竖条指示"导航风格的老项目或设计规范,官方在components/menu/demo/menu-v4.tsx中给出了一个标为 debug 的示例(对应文档 components/menu/demo/menu-v4.md),仅通过ConfigProvider覆盖 8 个组件级 Token,即可在 v5 组件上完整还原 v4 的 Menu 观感。读完本文,你将掌握这套 Token 的每个取值含义、其背后的样式生成原理,以及如何按需微调成自己的"类 v4"导航样式。

V4 风格 Menu 的视觉特征

在动手配置之前,先明确"V4 样式"到底指什么。对比当前版本 Menu 的默认外观(圆角菜单项、左右留白、hover 灰底),V4 风格主要包含以下特征:

  • 直角布局:菜单项与子菜单项不设圆角;
  • 零横向外边距:菜单项横向紧贴容器,没有margin-inline留白;
  • 左侧选中指示条:inline 模式下选中项左侧有一条约 3px 的竖条(V4 经典"墨条");
  • 品牌蓝交互色:hover 与选中文字均为#1890ff(V4 主色);
  • 浅蓝选中底色:选中项背景为#e6f7ff(V4 的item-selected-bg),hover 无底色变化;
  • 紧凑密度:菜单项高度、间距沿用 V4 的紧凑规格。

这些特征全部可以通过 Menu 组件级 Token 精确还原,无需写任何自定义 CSS。

完整示例:直接可运行的还原代码

以下代码完整来自官方 demo(components/menu/demo/menu-v4.tsx),它定义了一份包含普通项、带图标项、二级与三级子菜单、外部链接项的数据,并在ConfigProvider中集中覆盖 Menu Token:

import React, { useState } from 'react'; import { AppstoreOutlined, CalendarOutlined, LinkOutlined, MailOutlined, SettingOutlined, } from '@ant-design/icons'; import { ConfigProvider, Menu, Switch, Typography } from 'antd'; import type { MenuProps } from 'antd'; type MenuItem = Required<MenuProps>['items'][number]; const items: MenuItem[] = [ { key: '1', icon: <MailOutlined />, label: 'Navigation One', }, { key: '2', icon: <CalendarOutlined />, label: 'Navigation Two', }, { key: 'sub1', icon: <AppstoreOutlined />, label: 'Navigation Two', children: [ { key: '3', label: ( <Typography.Text ellipsis> Ant Design, a design language for background applications, is refined by Ant UED Team </Typography.Text> ), }, { key: '4', label: 'Option 4' }, { key: 'sub1-2', label: 'Submenu', children: [ { key: '5', label: 'Option 5' }, { key: '6', label: 'Option 6' }, ], }, ], }, { key: 'sub2', label: 'Navigation Three', icon: <SettingOutlined />, children: [ { label: 'Option 7', key: '7' }, { label: 'Option 8', key: '8' }, { label: 'Option 9', key: '9' }, { label: 'Option 10', key: '10' }, ], }, { key: 'link', icon: <LinkOutlined />, label: ( <a href="https://ant.design" target="_blank" rel="noopener noreferrer"> Ant Design </a> ), }, ]; const App: React.FC = () => { const [mode, setMode] = useState<'vertical' | 'inline'>('inline'); const changeMode = (value: boolean) => { setMode(value ? 'vertical' : 'inline'); }; return ( <> <Switch onChange={changeMode} /> Change Mode <br /> <br /> <ConfigProvider theme={{ components: { Menu: { itemBorderRadius: 0, subMenuItemBorderRadius: 0, itemHoverColor: '#1890ff', itemSelectedColor: '#1890ff', itemSelectedBg: '#e6f7ff', activeBarWidth: 3, itemMarginInline: 0, itemHoverBg: 'transparent', }, }, }} > <Menu style={{ width: 256 }} defaultSelectedKeys={['1']} defaultOpenKeys={['sub1']} mode={mode} items={items} /> </ConfigProvider> </> ); }; export default App;

要点解读:

  • 示例默认mode="inline",通过Switch可在inlinevertical之间即时切换,用于观察两种布局下同一套 Token 的效果;
  • defaultSelectedKeys={['1']}defaultOpenKeys={['sub1']}用于指定初始选中项与展开的子菜单(对应 Menu API 文档 中的同名属性);
  • items使用Required<MenuProps>['items'][number]推导类型,保证每个菜单项的结构合法;
  • 菜单项 label 中可以直接渲染Typography.Text<a>链接等任意 ReactNode,这也是 Menu items 泛型设计的典型用法。

八个 Token 逐一解析:V4 还原的关键配置

下表汇总了示例中 8 个 Token 的作用、示例取值,以及它们在当前仓库源码中的默认值(默认值取自 components/menu/style/index.ts 的prepareComponentToken):

Token作用示例取值源码默认值默认值来源
itemBorderRadius菜单项圆角0borderRadiusLGstyle/index.ts
subMenuItemBorderRadius弹出子菜单内菜单项圆角0borderRadiusSMstyle/index.ts
itemHoverColor菜单项 hover 文字颜色#1890ffcolorTextstyle/index.ts
itemSelectedColor选中项文字颜色#1890ffcolorPrimarystyle/index.ts
itemSelectedBg选中项背景色#e6f7ffcontrolItemBgActivestyle/index.ts
activeBarWidthinline 模式选中指示条宽度30(不显示指示条)style/index.ts
itemMarginInline菜单项横向外边距0marginXXSstyle/index.ts
itemHoverBg菜单项 hover 背景色transparentcolorBgTextHoverstyle/index.ts

可以发现,V4 还原的核心逻辑是"把 v5 引入的新视觉特征全部归零或替换":

  1. 圆角归零itemBorderRadiussubMenuItemBorderRadius置为0,恢复 V4 的直角菜单项(注意后者只作用于弹出层中的子菜单项,见 style/index.ts);
  2. 交互色替换itemHoverColoritemSelectedColor固定为 V4 主色#1890ff,不随colorPrimary主题变量漂移;
  3. 选中态重塑itemSelectedBg使用 V4 经典的浅蓝#e6f7ffitemHoverBg置为transparent去掉 v5 的 hover 灰底,只保留文字变蓝;
  4. 指示条开启activeBarWidth: 3激活 inline 模式左侧竖条,itemMarginInline: 0让竖条与容器边缘对齐,形成 V4 的"贴边墨条"。

源码原理:这些 Token 如何驱动样式生成

activeBarWidth:inline 模式的左侧竖条

在 components/menu/style/theme.ts 中,inline 模式为每个-item生成了一个::after伪元素:

[`${componentCls}-item`]: { position: 'relative', '&::after': { position: 'absolute', insetBlock: 0, insetInlineEnd: 0, borderInlineEnd: `${unit(activeBarWidth)} solid ${itemSelectedColor}`, transform: 'scaleY(0.0001)', opacity: 0, ... }, },

也就是说,竖条本质上是一条border-inline-end,宽度正是activeBarWidth,颜色跟随itemSelectedColor。默认未选中时通过scaleY(0.0001)opacity: 0隐藏;选中时切换为scaleY(1)opacity: 1,并配合motionDurationMid的过渡实现 V4 时代的"滑出"动效。示例将宽度设为3并令itemSelectedColor#1890ff,即还原 V4 的经典蓝条。

值得注意的是activeBarWidth的默认值是0(见 style/index.ts),这正是 v5 默认不显示左侧指示条的原因——手动赋值为3是开启该特性的开关。

itemMarginInline:影响菜单项实际宽度

在 components/menu/style/vertical.ts 中,inline/vertical 模式下的菜单项宽度并非简单的100%,而是由itemWidth决定:

[`${componentCls}-item, ${componentCls}-submenu-title`]: { ... marginInline: itemMarginInline, width: itemWidth, },

itemWidth的推导逻辑见 style/index.ts:

itemWidth: activeBarWidth ? `calc(100% + ${activeBarBorderWidth}px)` : `calc(100% - ${itemMarginInline * 2}px)`,
  • activeBarWidth0(v5 默认)时,菜单项宽度为100%减去两侧itemMarginInline,即默认marginXXS(4px)的左右留白;
  • 当启用指示条后,宽度变为calc(100% + activeBarBorderWidth),配合itemMarginInline: 0,竖条能够紧贴容器右缘,实现 V4 的贴边效果。

这解释了为什么示例必须同时设置activeBarWidth: 3itemMarginInline: 0:二者共同作用才能得到"容器内满宽 + 右缘竖条"的 V4 形态。

圆角与背景:作用于不同层级

  • itemBorderRadius直接作用于-item-submenu-title(见 style/index.ts);
  • subMenuItemBorderRadius只作用于弹出层(popup)中的菜单项(style/index.ts),所以示例将两者都设为0以保证所有层级的菜单项都是直角;
  • itemHoverBg仅在非水平模式下、且未选中/未展开的项上生效(theme.ts),置为transparent后 hover 只剩文字变色,与 V4 行为一致;
  • 选中态背景itemSelectedBg通过& ${componentCls}-item-selectedbackgroundColor生效(theme.ts)。

注意事项与扩展建议

  • 作用范围:Token 通过ConfigProvider注入,会影响该 Provider 子树内所有Menu 实例(包括子菜单弹出层、以及 Layout Sider 等组合场景)。如需全局统一"类 v4"导航,可直接把这段theme.components.Menu配置放到应用根部的ConfigProvider;若只想影响局部,可像示例一样缩小 Provider 包裹范围。
  • debug 标记:该示例在 Menu 文档 中被标记为 debug,属于"风格兼容演示"而非推荐默认样式,使用时请确认团队设计规范确实需要 V4 观感。
  • 暗色主题:若同时使用theme="dark"的 Menu,暗色 Token(如darkItemBgdarkItemSelectedBg等,见 style/index.ts)仍会接管颜色,上述亮色配置需另行针对暗色 Token 调整。
  • 继续微调:在还原基础上可进一步调整itemHeight(V4 更紧凑的 40px 高度)、itemPaddingInlinegroupTitleColor等 Token(完整清单见 style/index.ts 的ComponentToken定义),即可得到自定义密度与配色;同一文件中的旧版 Token 别名(如colorItemTextSelectedradiusItem)已标记 deprecated,新代码应使用上述标准名称。
  • 验证方式:该 demo 同时被快照测试覆盖(见components/menu/__tests__/__snapshots__/demo.test.tsx.snap中的menu-v4.tsx用例),修改 Token 后可通过npm test运行组件测试确认样式输出无回归。

小结

V4 风格 Menu 的还原不需要任何 hack 或自定义 CSS:activeBarWidthitemMarginInlineitemBorderRadiusitemSelectedBg等 8 个组件 Token 的组合,就能完整复刻"直角贴边 + 左侧蓝条 + 蓝色交互 + 浅蓝选中"的经典观感。理解 theme.ts 中指示条伪元素与itemWidth的推导逻辑(vertical.ts),还能让你在此基础上自由派生属于自己的菜单风格。

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 4:02:36

用买房逻辑搞懂期权:Call、Put、行权与指派实战指南

期权这玩意儿&#xff0c;很多老股民一听就头大。Call、Put、行权、指派&#xff0c;每个字都认识&#xff0c;连在一起就不知道在说啥。我当年刚接触期权的时候也差不多&#xff0c;看了几本书&#xff0c;能背概念&#xff0c;但一问“行权和指派到底怎么发生的”&#xff0c…

作者头像 李华
网站建设 2026/9/19 3:58:48

智能问答知识库,TaoToken 在 embedding 与 chat 两处消耗 Token

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 3:58:10

DeepSeek Harness部署指南:Node+nvm+pnpm三位一体配置

1. 项目概述&#xff1a;这不是一个“安装包”&#xff0c;而是一套大模型服务编排体系你搜“DeepSeek Harness”时&#xff0c;大概率会撞上一堆零散的报错截图、半截命令行日志、还有人问“harness和agent到底啥区别”。别急——这根本不是个传统意义上的软件安装问题。DeepS…

作者头像 李华