React and ANTD component libraries
React is the mainstream front-end development framework at present. The popular front-end frameworks are Angular,Vue and React. The specific selection depends on the project requirements.
Antd is a component library developed based on React. The Ant Financial team quit. Currently, there are many users, many components and friendly documents.
What I did this time was to use the Menu component of ANTD with React to change the browser address and highlight the requirements of the corresponding navigation Menu.
The specific implementation
1. This time, [email protected] is used as the front-end route. For convenience, HashRouter is directly used:
// Layout/index.js
// Import the necessary components
import React, { PureComponent } from 'react';
import { NavLink, Route, Switch, Redirect, Link } from 'react-router-dom';
import { Menu, Icon } from 'antd';
import 'assets/layout/index.scss';
const MenuItem = Menu.Item;
const SubMenu = Menu.SubMenu;
Copy the code
2. Configure routes
// The front end needs to maintain a routing table, whether static configuration or from the back end, antD Menu component uses the key as the unique identifier of the Menu item, here we directly use path as the key (if it is a submenu, use title as the key), When the browser hash is changed, it is easier to retrieve menu items (note that the key must not be repeated, otherwise it will not work).
// The submenu in the menu configuration can be any level
const menuConfig = [
{
title: 'home'.icon: 'pie-chart'.path: '/home'
},
{
title: 'buy'.icon: null.children: [{title: 'details'.icon: null.path: '/buy/detail'}]}, {title: 'management'.icon: null.children: [{title: 'performance'.icon: null.children: [{title: 'price'.icon: null.path: '/management/detail/price'.children: [{title: 'shares'.icon: null.path: '/management/ddd'}]}]}];Copy the code
-
Components are written
- Implementation idea:
(1). In order to achieve an open-ended route rendering and highlighting menu, I use a recursive implementation here.
(2). When the browser address is changed, the corresponding menu item should be highlighted. This may be a first-level menu or a sub-level menu, so the corresponding sub-menu needs to be expanded
(3) to monitor the browser address change, use the react – the router to render the component in the props will receive the history of the object, the object has a listen, you can add a custom event monitoring, the default parameters for an object: {hash: “” pathname: “” search: “” state: undefined }
- Begin to implement
// 1. Define a menu node class, which will be used when initializing routing table data: class MenuNode { constructor(menuItem, parent = null) { this.key = menuItem.path || menuItem.title; this.parent = parent; }}// 2. React component // defaultOpenKeys and defaultSelectedKeys are passed to the Menu component to specify the currently open Menu item export default class Index extends PureComponent { constructor(props) { super(props); this.state = { defaultOpenKeys: [].defaultSelectedKeys: []};this.menuTree = []; } componentDidMount = (a)= > { const history = this.props.history; // Initialize the routing table: this.initMenu(menuConfig); // You need to manually set the current menu once after rendering, because history's listen will not fire at this point this.setActiveMenu(history.location); this.unListen = history.listen(this.setActiveMenu); }; componentWillUnmount = (a)= > { // Remove the listener this.unListen(); }; // serialize the routing table initMenu = (config, parent = null) = > { for (let menuItem of config) { if (menuItem.children) { // This method is performed recursively on the children of a menuItem if it has children, with the current menuItem as the parent this.initMenu(menuItem.children, new MenuNode(menuItem, parent)); } else { // If this route does not have children, it is a first-level route and is placed directly into menuTree this.menuTree.push(newMenuNode(menuItem, parent)); }}//menuTree stores a single menuNode object. By checking whether menuNode is a valid parent, you can determine whether it is a level 1 route or a route under the sub-menu }; // This method is the core method for implementing menu highlighting setActiveMenu = location= > { // Get the hash path of the current browser const pathname = location.pathname; // for (let node of this.menuTree) { // Use the re to determine whether the current browser path matches the key in the menu item. This re can match dynamic paths (similar to /product/:id), so even dynamic routes can highlight the corresponding menu const isActivePath = new RegExp(` ^${node.key}`).test(pathname); if (isActivePath) { const openKeys = []; const selectedKeys = [node.key]; // Check whether the current menu has a parent menu. If so, expand the parent menu while (node.parent) { openKeys.push(node.parent.key); node = node.parent; } this.setState({ defaultOpenKeys: openKeys, defaultSelectedKeys: selectedKeys }); return; }}// If none of the routes match, close the menu this.setState({ defaultSelectedKeys: [].defaultOpenKeys: []}); };// It is used for rendering routes, which can achieve arbitrary levels of rendering through recursion renderMenuItem = menuArr= > { const ret = menuArr.map(item= > { if (item.children) { return ( <SubMenu title={item.title} key={item.path || item.title} > {this.renderMenuItem(item.children)} </SubMenu> ); } else { return ( <MenuItem title={item.title} key={item.path}> <Link to="item.path">{item.title}</Link> </MenuItem>); }});return ret; }; render() { return ( <div> <div> <div style={{ width: 150}} > <div>The current menu: {this. State. DefaultSelectedKeys [0]}</div> <Menu mode="inline" theme="dark" selectedKeys={this.state.defaultSelectedKeys} openKeys={this.state.defaultOpenKeys} onSelect={this.selectMenuItem} onOpenChange={this.openMenu} > {this.renderMenuItem(menuConfig)} </Menu> </div> </div> <div id="main"> heelo,react </div> </div>); }}Copy the code
-
rendering