UNPKG

@cc-dev-kit-test/console-components-console-menu

Version:

React component for Alibaba Cloud.

344 lines (263 loc) 14.2 kB
# @alicloud/console-components-console-menu 为阿里云控制台提供标准的应用级别的导航菜单,也可以应用在其他的中后台产品中 ### 1.0 的新特性 ##### 组件模块 ###### 基础导航菜单 在之前的版本中默认导出的 `<ConsoleMenu>` 组件包含了完整的路由行为,在 1.0 中,默认导出的组件 **不再包含** 路由行为,你可以根据自己项目中的路由环境来映射 `<ConsoleMenu>` 的展现和行为(如设置 `activeKey` 等)。 ```javascript import ConsoleMenu from '@alicloud/console-components-console-menu' import { Route, Link } from 'react-router-dom' const mapLocationToActiveKey = (location) => { if (!location || !location.pathname || location.pathname === '/') { return 'overview' } return location.pathname.replace(/^\//, '') } const App = () => ( <Route> { ({ location }) => ( <ConsoleMenu header="Aliyun Console" activeKey={location.pathname} > <ConsoleMenu.Item key="overview"> <Link to="/overview">概览</Link> </ConsoleMenu.Item> <ConsoleMenu.Item key="list"> <Link to="/list">列表</Link> </ConsoleMenu.Item> <ConsoleMenu.SubMenu key="logs"> <ConsoleMenu.Item key="daily"> <Link to="/daily">日常</Link> </ConsoleMenu.Item> <ConsoleMenu.Item key="prod"> <Link to="/prod">生产</Link> </ConsoleMenu.Item> </ConsoleMenu.SubMenu> </ConsoleMenu> ) } </Route> ) ``` 你也可以用结构化的描述来定制 `<ConsoleMenu>` 的内容。下面的示例作用和上面的作用完全相同: ```javascript import ConsoleMenu from '@alicloud/console-components-console-menu' import { Route, Link } from 'react-router-dom' const mapLocationToActiveKey = (location) => { if (!location || !location.pathname || location.pathname === '/') { return 'overview' } return location.pathname.replace(/^\//, '') } const renderAsLink = ({ key, label }) => ( <Link to={`/${key}`}>{label}</Link> ) const items = [ { key: 'overview', label: '概览', render: renderAsLink }, { key: 'list', label: '列表', render: renderAsLink }, { key: 'logs', label: '列表', items: [ { key: 'daily', label: '日常', render: renderAsLink }, { key: 'prod', label: '生产', render: renderAsLink, visible: false }, ] }, ] const App = () => ( <Route> { ({ location }) => ( <ConsoleMenu header="Aliyun Console" items={items} activeKey={location.pathname} /> ) } </Route> ) ``` ###### 带有路由功能的导航菜单 如果你的项目使用了 `dva^2.0.0` ,我们也提供了 `<RoutableMenu>` 组件来提供与之适配的路由功能。 _(截止目前为止, `<RoutableMenu>` 必须使用 items 进行结构化的传值,使用组件声明方式来编写子组件的方式可能会存在问题,我们计划在不久之后来修复这个问题)_ ```javascript import RoutableMenu from '@alicloud/console-components-console-menu/RoutableMenu' const items = [ { // 在当前路由路径为 `/overview` 时将该 Item 变为选中状态 key: '/overview', label: '概览', // 点击该 Item 会跳转至 `/overview` to: '/overview' }, { key: '/product/:region', label: '产品', to: '/product/cn-hangzhou' }, { // 在当前路由路径匹配 `/instance/:region?` 时将该 Item 变为选中状态 key: '/instance/:region?', label: '实例', to: (routeProps, item) => { // 该方法并不是我们推荐的做法,只是为了表示 `to` 可以用函数表达式来声明: // 第一个参数是当前的 route props ,第二个参数是当前的 item 的结构化信息 // 你可以利用这些信息来动态地返回需要进行跳转的 pathname 或 location // 下面的这个例子使用了当前路由的匹配信息(注意:并不是对于该 item 的匹配) // 来进行相应的跳转。如果当前的路由中包含 param: region ,(譬如从 // `/product/cn-hangzhou` 点击该 item 将会跳转到 `/instance/cn-hangzhou` // // 在实际项目中的最佳实践是直接派发父级 pathname ,然后在 <Route> 中通过上下文 // 或者其他方式进行路由重定向 // const { match: { params: { region } = {} } = {} } = routeProps return `/instance/${region}` }, // 除了使用 `key` 来匹配单个的路由路径之外,还可以使用 `activePathPatterns` 来 // 尝试匹配多个路由路径,`<RoutableMenu>` 内置的匹配算法将会在尝试将当前的路径匹配 // `key` 失败之后,按照 `activePathPatterns` 指定的顺序依次进行尝试匹配,一旦匹配 // 成功,则将该 Item 变为选中状态 activePathPatterns: [ '/instance/:regionId/:instanceId', ], }, { key: 'logs', label: '列表', items: [ { key: '/daily', label: '日常', // 使用 href 将使用超链接的方式打开指定的链接,区别于应用内的路由跳转 href: 'https://daily.project.com', }, { key: '/prod', label: '生产', to: '/prod', }, ] }, ] const App = () => ( <RoutableMenu header="Aliyun Console" items={items} /> ) ``` #### 可高度定制的组件 所有的展示组件( Presentation Components )都已经通过`StyledComponents`导出,这些组件可以作为样式自定义的切入点。如果你希望自定义 `<ConsoleMenu>` 的样式,可以使用 `styled-components` 的方式对样式进行修改,而不用担心对全局或其他模块产生冲突。如这个例子所示: ```javascript import styled from 'styled-components' import ConsoleMenu, { StyledComponents } from '@alicloud/console-components-console-menu' const CustomizedConsoleMenu = styled(ConsoleMenu)` ${StyledComponents.Item} { font-size: 14px; } /* any css is ok here */ ` // CustomizedConsoleMenu中的Item样式已经修改 // ConsoleMenu的样式没有变化 // 可以将CustomizedConsoleMenu理解为ConsoleMenu的“fork” const App = () => ( <CustomizedConsoleMenu header="Aliyun Console" items={[{ key: 'overview', label: '概览' }]} /> ) ``` ### API 变动参考 #### Props | 旧版本 | 1.0 | 说明 | | :---: | :---: | :--- | | `config.title` | `header` | `config` 属性中的 `title` 和 `navs` 定义分别调整为 props 中的 `header` 和 `items` ,绝大部分属于语义化和结构化的调整 | | `config.navs` | `items` | 同上,内部元素的调整可以参考 **Props.config.navs v.s. Props.items** 来浏览变更 | | `onClick` | `onItemClick` | 语义化调整 | | `open` | -- | 该属性已经被移除,导航菜单本身不应具备「展开」和「收起」的行为,这给其他组件的设计带来了一些不利因素;现在这些行为统一归纳到 `@ali/wind-rc-app-layout` 并受其控制,导航菜单不再对这些行为负责 | | `toggleOpen` | -- | 该属性已经被移除,导航菜单本身不应具备「展开」和「收起」的行为,这给其他组件的设计带来了一些不利因素;现在这些行为统一归纳到 `@ali/wind-rc-app-layout` 并受其控制,导航菜单不再对这些行为负责 | | `decentSubNav` | -- | 该属性已经被移除,现在该行为已经内置在默认的行为中,当一个父节点中的所有子节点都被设置成不可见时,该父节点也会相应地从当前组件树中移除 | | `params` | -- | 该属性已经被移除,可以使用 `RoutableMenu` 并声明 item 元素的 `to` 属性,由于该属性可以被声明为一个函数,该函数将在每次路由跳转之前执行并将返回结果作为跳转的目标 pathname 或 location,理论上你可以编写任何代码来执行路由跳转 | | `level` | -- | 该属性已经被移除,在新的设计规范中,L2 导航被调整到应用的内容区,相关的功能请参考 `@ali/wind-rc-page` | | `history` | -- | 该属性已经被移除,你可以直接使用 `<RoutableMenu>` 来获得操控应用路由的能力 | | `location` | -- | 该属性已经被移除,你可以直接使用 `<RoutableMenu>` 来获得操控应用路由的能力 | #### Props.config.navs[i] v.s. Props.items[i] | config.navs[i] | items[i] | 说明 | | :---: | :---: | :--- | | `key` | `key` | 在之前的版本中 key 既可以当做需要进行跳转的路径,也可以当做进行尝试匹配的路径,但是在新版本中,key 只会作为进行尝试匹配的路径,你需要使用 `to` 来定义需要进行跳转的路径。 | | -- | `to` | 在之前的版本中只需要定义 key 即可同时当做跳转路径和需要尝试匹配的路径,在新版本中,你 **必须** 定义 `to` 属性才可以正常进行跳转,具体用法可以参考 [RoutableItemDescriptor API](#RoutableItemDescriptor) | | -- | `linkProps` | 自定义内置 `Link` 组件的 props ,如果定义了 `to` ,`linkProps` 将透传至 React-Router [Link](https://reacttraining.com/react-router/web/api/Link) 组件;如果定义了 `href` ,则 `linkProps` 将透传至 `<a>` ,如 `target="_blank"` 等 | | `title` | `label` | 定义默认显示的内容 | | `hide` | `visible` | 是否显示该菜单项,注意 `visible` 和 `hide` 的值是相反的 | | `url` | `href` | 使用超链接的方式打开指定的链接,区别于应用内的路由跳转 | | `highlight` | `activePathPatterns` | 需要尝试进行匹配并进行高亮的路由路径集合 | | `subNav` | `items` | 子菜单项 | | `type` | -- | 该属性已经被移除,现在每个 Item 的类型由 `label` / `to` / `href` 来定义:当只有 `label` 声明时,该 Item 将不具任何特质,等同于原有的 `type: "title"` ;声明了 `label` 的 Item 将具备默认的应用内路由跳转的能力,等同于原有的 `type: "link"` ;声明了 `href` 的 Item 将使用超链接的方式打开指定的链接,等同于原有的 `type: "stateLink"` | | `navs` | -- | 该属性已经被移除,在最新的视觉和交互规范中,L2 导航被放置到了右侧的内容区,你可以将 `<ConsoleMenu>` 传入 `@ali/wind-rc-page` 的 `<Page.Content>` 的 `menu` 属性中 | | `open` | -- | 该属性已经被移除,请使用组件的属性 `openKeys` 或 `defaultOpenKeys` 来进行手动控制 | ##### 使用 L2 导航 ```javascript import RoutableMenu from '@alicloud/console-components-console-menu/RoutableMenu' import Page from '@ali/wind-rc-page' const menu = ( <RoutableMenu type="secondary" items={[]} /> ) const MyPage = () => ( <Page> <Page.Content menu={menu}> Hello, World </Page.Content> </Page> ) ``` #### 视觉和交互 - 移除关于 `width` / `min-width` 的限制,组件宽度自适应容器宽度 - 更新主题颜色,适配最新的设计标准 ## 安装 ### 同级依赖**1.0 版本**中,`<ConsoleMenu>` 组件的同级依赖( peer dependencies )增加了 `styled-components` 为组件提供基础的样式能力,使用了 React Hooks 封装业务逻辑,并应用了一些其他的底层更新带来的问题修复和特性。请保证你的项目正确安装了下面的这些依赖 | 依赖名称 | 版本 | | :--- | :---: | | `styled-components` | `^4.2.0` | | `react` | `^16.8.0` | | `react-dom` | `^16.8.0` | | `prop-types` | `^15.7.0` | | `@alicloud/console-components` | `^1.0.0` | ### 安装最新版本 ```bash npm i -S @alicloud/console-components-console-menu ``` ## 使用示例 ### 基本使用 下面的示例展示了使用 `<ConsoleMenu>` / `<ConsoleMenu.Item>` 以及 `<ConsoleMenu.SubMenu>` 等组件,组合而成一个完整的视图级别的导航菜单 [MDXInstruction:importDemo:BasicDemo](./stories/basic.tsx) ### 次级导航 使用 `type="secondary"` 可以将导航的样式变为次级导航,功能与主导航一致 [MDXInstruction:importDemo:SecondaryNavDemo](./stories/secondary.tsx) ### 组件受控 使用 `activeKey` 可以控制导航的当前选中的 key ,下面的示例展示了如何结合 `<Route>` 和 `<Link>` 来自定义受路由控制的导航菜单 [MDXInstruction:importDemo:ControlledMenuDemo](./stories/controlled-menu.tsx) ### 使用结构化声明 使用 `items` 可以将所有的菜单项进行结构化声明,就像 `Table.dataSource` 一样 [MDXInstruction:importDemo:ItemsDeclarationDemo](./stories/with-items-declaration.tsx) ### 可路由的导航菜单 使用 `<RoutableMenu>` 可以获得常用的路由功能,如将当前路由路径映射到对应的 `activeKey` ,以及点击菜单项之后的路由跳转等功能 _该功能同级依赖于 `dva^2.0.0` ,请确保你的项目中安装了该依赖的正确版本_ [MDXInstruction:importDemo:RoutableMenuDemo](./stories/routable-menu.tsx) ### 可切换header的导航菜单 可以通过配置`headers`来为header提供数据源,当提供headers之后,header类型应为string非ReactNode, 否则会导致下拉菜单不能勾选☑️ [MDXInstruction:importDemo:SwitchHeaderMenuDemo](./stories/switch-header.tsx) ### 可切换product的导航菜单 可以通过配置`productSource`来为product下拉选择提供数据源,通过设置`productValue`来确定当前选择的产品值 [MDXInstruction:importDemo:SwitchProductMenuDemo](./stories/switch-product.tsx) ## APIs ### ConsoleMenu [MDXInstruction:renderInterface:IConsoleMenuProps](./api-json/api.json) #### IItemDescriptor [MDXInstruction:renderInterface:IItemDescriptor](./api-json/api.json) ### RoutableMenu 继承自 `<ConsoleMenu>` ,重复的属性不再赘述,请参阅 [ConsoleMenu API](#consolemenu) [MDXInstruction:renderInterface:IRoutableMenuProps](./api-json/api.json) #### IRoutableItemDescriptor 继承自 `IItemDescriptor` ,重复的属性不再赘述,请参阅 [IItemDescriptor](#iitemdescriptor) [MDXInstruction:renderInterface:IRoutableItemDescriptor](./api-json/api.json)