Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >React 系列 - 写出优雅的路由

React 系列 - 写出优雅的路由

作者头像
捷义
发布于 2019-02-18 06:46:32
发布于 2019-02-18 06:46:32
1K00
代码可运行
举报
文章被收录于专栏:有刻有刻
运行总次数:0
代码可运行

前言

自前端框架风靡以来,路由一词在前端的热度与日俱增,他是几乎所有前端框架的核心功能点。不同于后端,前端的路由往往需要表达更多的业务功能,例如与菜单耦合、与标题耦合、与“面包屑”耦合等等,因此很少有拆箱即用的完整方案,多多少少得二次加工一下。

1. UmiJS 简述

优秀的框架可以缩短 90% 以上的无效开发时间,蚂蚁的 UmiJS 是我见过最优雅的 React 应用框架,或者可以直接说是最优雅的前端解决方案(欢迎挑战),本系列将逐步展开在其之上的应用,本文重点为“路由”,其余部分后续系列继续深入。

2. 需求概述

动码之前先构想下本次我们要实现哪些功能:

  1. 路由需要耦合菜单,且需要对菜单的空节点自动往下补齐;
  2. 路由中总要体现模板的概念,即不同的路由允许使用不用的模板组件;
  3. 模板与页面的关系完全交由路由组合,不再体现于组件中;
  4. 需要实现从路由中获取当前页面的轨迹,即“面包屑”的功能;
  5. 实现从路由中获取页面标题;

上述每一点的功能都不复杂,若不追求极致,其实默认的约定式路由基本能够满足需求(详情查询官方文档,此处不做展开)。

3. 开码

3.1 菜单

先从菜单出发,以下应当是一个最简洁的目录结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const menu = [
  {
    name: '父节点',
    path: 'parent',
    children: [{
      name: '子页面',
      path: 'child'
    }]
  }
];

使用递归补齐 child 路径:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
const formatMenu = (data, parentPath = `${define.BASE_PATH}/`) => {
  return data.map((item) => {
    let { path } = item;
    if (!reg.test(path)) {
      path = parentPath + item.path;
    }
    const result = {
      ...item,
      path
    };
    if (item.children) {
      result.children = formatMenu(item.children, `${parentPath}${item.path}/`);
    }

    return result;
  });
}

菜单的子节点才是真正的页面,所以若当前路径是父节点,我们期望的是能够自动跳转到父节点写的第一个或者特定的页面:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const redirectData = [];
const formatRedirect = item => {
  if (item && item.children) {
    if (item.children[0] && item.children[0].path) {
      redirectData.push({
        path: `${item.path}`,
        redirect: `${item.children[0].path}`
      });
      item.children.forEach(children => {
        formatRedirect(children);
      });
    }
  }
};
const getRedirectData = (menuData) => {
  menuData.forEach(formatRedirect);
  return redirectData
};

3.2 路由组装

而后便是将自动跳转的路径组装入路由节点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const routes = [
  ...redirect,
  {
    path: define.BASE_PATH,
    component: '../layouts/BasicLayout',
    routes: [
      {
        path: `${define.BASE_PATH}/parent`,
        routes: [
          {
            title: '子页面',
            path: 'child',
            component: './parent/child',
          }
        ],
      },
      {
        component: './404',
      }
    ]
  }
];

路由配置最后需要注入配置文件 .umirc.js:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { plugins } from './config/plugins';
import { routes } from './config/routes';

export default {
  plugins,
  routes
}

3.3 模板页

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { Layout } from 'antd';
import React, { PureComponent, Fragment } from 'react';
import { ContainerQuery } from 'react-container-query';
import DocumentTitle from 'react-document-title';

import { query } from '@/utils/layout';
import Footer from './Footer';
import Context from './MenuContext';

const { Content } = Layout;

class BasicLayout extends PureComponent {

  render() {
    const {
      children,
      location: { pathname }
    } = this.props;
    const layout = (
      <Layout>
        <Layout>
          <Content>
            {children}
          </Content>
          <Footer />
        </Layout>
      </Layout>
    );
    return (
      <Fragment>
        <DocumentTitle title={this.getPageTitle(pathname)}>
          <ContainerQuery query={query}>
            {params => (
              <Context.Provider>
                {layout}
              </Context.Provider>
            )}
          </ContainerQuery>
        </DocumentTitle>
      </Fragment>
    );
  }
}

export default BasicLayout;

结合路由与菜单获取面包屑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getBreadcrumbNameMap() {
  const routerMap = {};
  let path = this.props.location.pathname;
  if (path.endsWith('/')) {
    path = path.slice(0, path.length - 1);
  }

  const mergeRoute = (path) => {
    if (path.lastIndexOf('/') > 0) {
      const title = this.getPageTitle(path);
      if (title) {
        routerMap[path] = {
          name: title,
          path: path
        };
      }
      mergeRoute(path.slice(0, path.lastIndexOf('/')));
    }
  };
  const mergeMenu = data => {
    data.forEach(menuItem => {
      if (menuItem.children) {
        mergeMenu(menuItem.children);
      }
      routerMap[menuItem.path] = {
        isMenu: true,
        ...menuItem
      };
    });
  };
  mergeRoute(path);
  mergeMenu(this.state.menuData);
  return routerMap;
}

从路由中获取 PageTitle:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getPageTitle = (path) => {
  if (path.endsWith('/')) {
    path = path.slice(0, path.length - 1);
  }
  let title;
  this.props.route.routes[0].routes.forEach(route => {
    if (route.path === path) {
      title = route.title;
      return;
    }
  })
  return title;
};

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
简单粗暴的react路由
我要的是简单粗暴的路由 习惯了 vue-router 路由的用法,再用react-router总感觉挺麻烦的。 那么就自己封装一个吧 1.封装多级路由的情况 ————文件名为routerView.js import React from 'react'; import {Switch, Redirect, Route} from 'dva/router'; export default (props)=>{ return <Switch>{ props.routes.map((item, i
super.x
2019/04/12
8500
简单粗暴的react路由
React 折腾记 - (1) React Router V4 和antd侧边栏的正确关联及动态title的实现
collapsed,onCollapse这些是控制侧边栏缩小的,接受的是外部的props
CRPER
2018/08/28
3K0
React 折腾记 - (1) React Router V4 和antd侧边栏的正确关联及动态title的实现
Vue3动态添加路由及生成菜单
最近在尝试用Vue3开发个管理平台项目,一切都是从头开始,基本框架搭建,熟悉Vue3写法,编写登录页,编写路由守卫,上面功能已基本完成,开始编写首页布局,用Vue3就必须用Router4.x版本,所以之前的代码迁移过来之后发现,动态路由不生效,查了很多资料,最后发现,Router4中,去掉了 router.addRoutes ,只能使用 addRoute
青年码农
2021/01/18
16.6K8
Vue3动态添加路由及生成菜单
vue-element-admin el-admin 无限级路由缓存方案 记录
vue-element-admin 前置要点 每页都要有name 1. 修改 src\store\modules\permission.js 1.添加两个方法 /** * 生成扁平化机构路由(仅两级结构) * @param {允许访问的路由Tree} accessRoutes * 路由基本机构: * { * name: String, * path: String, * component: Component, * redirect: String, * child
余生
2021/01/13
8190
Vue3使用递归组件封装El-Menu多级菜单
明知山
2023/09/06
1K0
Vue3使用递归组件封装El-Menu多级菜单
React 动态菜单-不限级递归菜单树
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/159442.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/17
1.6K0
Vue手把手带你撸项目系列之动态面包屑
面包屑应该是我们在项目中经常使用的一个功能,一般情况下它用来表示我们当前所处的站点位置,也可以帮助我们能够更快的回到上个层级。
六小登登
2019/07/01
1.4K0
Vue手把手带你撸项目系列之动态面包屑
antd pro 网页title取不到问题解决
项目使用 antd-design-pro v5,今天同事说他那边跳转时候发现网页的title 错误。
星宇大前端
2022/11/07
8400
antd pro 网页title取不到问题解决
Vue 动态添加路由及生成菜单
写后台管理系统,估计有不少人遇过这样的需求:根据后台数据动态添加路由和菜单。 为什么这么做呢?因为不同的用户有不同的权限,能访问的页面是不一样的。 在网上找了好多资料,终于想到了解决办法。
谭光志
2020/09/28
3.7K0
大爱并发模式!React Router 路由跳转最佳实践的秘密
在 Next.js 大热之前,React Router 是 React 生态中,最流行的路由库。也是我最喜爱的路由库。不过随着版本的迭代,React Router 变得越来越庞大了。他的复杂度已经快要比得上一个框架了。
用户6901603
2024/06/07
4770
大爱并发模式!React Router 路由跳转最佳实践的秘密
使用ReactHook和context实现登录状态的共享
使用react hook 和应用上下文context进行一个自定义的hook的开发。
我已经洗完澡了
2019/10/14
5.3K0
React 折腾记 - (3) 结合Mobx实现一个比较靠谱的动态tab水平菜单,同时关联侧边栏
前言 动态tab水平菜单,这个需求很常见,特别是对于后台管理系统来说; 因为当我们侧边栏层级多了,你要找到一个子菜单,必须找,展开,点击. 而有了这个,我们就能节省不少时间,体验上来说也会改善不少 实
CRPER
2018/08/28
3.2K0
React 折腾记 - (3) 结合Mobx实现一个比较靠谱的动态tab水平菜单,同时关联侧边栏
聊聊React中的权限组件设计
权限管理是中后台系统中常见的需求之一。之前做过基于 Vue 的后台管理系统权限控制[1],基本思路就是在一些路由钩子里做权限比对和拦截处理。
前端森林
2022/03/30
2.8K0
聊聊React中的权限组件设计
React进阶篇(九)React Router
单页面应用(SPA)可以让Web应用看起来像多页面应用,URL变化时,不会向服务端发起请求,而是利用自身监听路由变化而更新UI。 通过使用React Router可以让Web应用根据不同URL渲染不同组件。
娜姐
2020/12/11
3K0
Vue+abp增加三级菜单
title: "Vue+abp增加三级菜单" publishDate: 2019-12-26 17:28:38 +0800 date: 2019-12-26 17:28:38 +0800 categories: Vue+abp增加三级菜单 position: problem ---
用户6362579
2019/12/30
1.3K0
Vue3+Elementplus引入面包屑功能
📐第 2 步 :编写获取路径的方法 matched获取访问网址在路由中的路径,并过滤掉item没有title的元素,因为需要用title填充面包屑的内容
知识浅谈
2023/09/26
7220
Vue3+Elementplus引入面包屑功能
React 折腾记 - (4) 侧边栏联动Tabs菜单-增强版(结合Mobx)
上个版本 :React 折腾记 - (3) 结合Mobx实现一个比较靠谱的动态tab水平菜单,同时关联侧边栏
CRPER
2018/08/28
3.8K0
React 折腾记 - (4) 侧边栏联动Tabs菜单-增强版(结合Mobx)
Uni&antd的ProLayout布局动态菜单实现及踩坑记录
ProLayout 高级布局是 Ant Design Pro 中的一个组件,可以提供一个标准又不失灵活的中后台标准布局,同时提供一键切换布局形态,自动生成菜单等功能。页面中需要承载内容时,可以使用 ProLayout 来减少布局成本。
德顺
2021/07/09
14.7K5
Umi&React动态修改title标题
在调整好菜单后,又发现一个问题,打开页面不显示标题,点击菜单的时候才会正常显示标题,再次点击当前菜单,标题又变的不太对了。
德顺
2021/07/12
6K0
Vue折腾记 - (2)写一个不大靠谱的面包屑组件
我把页面标题和面包屑封装到一起..就不用涉及到组件的通讯了, 不然又要去监听路由或者依赖状态去获取
CRPER
2018/08/28
5160
Vue折腾记 - (2)写一个不大靠谱的面包屑组件
推荐阅读
相关推荐
简单粗暴的react路由
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文