• react-router-dom5.0的路由拦截(路由守卫)实现


    react不同于vue,通过在路由里设置meta元字符实现路由拦截。在使用 Vue ,框架提供了路由守卫功能,用来在进入某个路有前进行一些校验工作,如果校验失败,就跳转到 404 或者登陆页面,比如 Vue 中的 beforeEnter 函数:

    ...
    router.beforeEach(async(to, from, next) => {
        const toPath = to.path;
        const fromPath = from.path;
    })
    ...
    

    demo 请狠狠的戳这里 ¥  http://download.lllomh.com/cliect/#/product/J615178556091098

    demo 请狠狠的戳这里 c   https://download.csdn.net/download/lllomh/12525114

    react实现路由拦截的基本思路还是利用Route 的render函数。通过判断拦截条件来实现不同的组件的跳转,从而实现拦截。在之前的版本中,React Router 也提供了类似的 onEnter 钩子,但在 React Router 4.0 版本中,取消了这个方法。React Router 4.0 以后采用了声明式的组件,路由即组件,要实现路由守卫功能,就得我们自己去写了。
    如果不使用路由守卫,Router 组件是这样子的:

    import * as React from 'react';
    import { HashRouter,Switch,Route,Redirect } from 'react-router-dom';
     
    import Index from "./page/index";
    import Home from "./page/home";
    import ErrorPage from "./page/error";
    import Login from "./page/login";
     
    export const Router = () => (
        <HashRouter>
            <Switch>
                <Route path="/" exact component={Index}/>
                <Route path="/login" exact component={Login}/>
                <Route path="/home" exact component={Home}/>
                <Route path="/404" exact component={ErrorPage}/>
                <Redirect to="/404" />
            </Switch>
        </HashRouter>
    );
    

    上面的 Router 组件,包含了三个页面:

    • 登陆
    • 主页
    • 404 页面
    • 以及四个路由:
    • 根路由
    • 登陆路由
    • 主页路由
    • 404 路由
    • 其中,根路由和 /home 路由,都定向到了主页路由。
    • 以上是一个基本的路由定义,可以在登陆/主页和 404 页面之间来回跳转,但也有一些问题:
    • 非登陆状态下,可以直接跳转到主页
    • 登陆状态下,也可以输入 /login 路由跳转到登录页
    • 现在,我们想完成这样的功能:
    • 非登陆状态下,无法直接跳转到主页,如果在非登陆状态下进行主页跳转,需要重定向至登陆路由
    • 登陆状态下,无法跳转至登录页,如果在登陆状态下进行登陆页跳转,需要重定向至主页路由
    • 要完成这个功能,有两种方案:
    • 在每个组件中,根据 props 上的 history 对象来进行跳转
    • 进行全局的路由守卫处理

    首先在跟目录src下创建一个routerMap.js文件,代码如下: 

    import Index from "./page/index";
    import Home from "./page/home";
    import ErrorPage from "./page/error";
    import Login from "./page/login";
    export default [
      { path: "/", name: "App", component: Index, auth: true },
      { path: "/home", name: "Home", component: Home, auth: true },
      { path: "/login", name: "Login", component: Login },
      { path: "/404", name: "404", component: ErrorPage },
    ];
    

     将 auth 设置为 true,表示该路由需要权限校验。
    然后,定义 Router 组件,在App.js中,该组件是经过高阶组件包装后的结果:

    //App.js
    import React, { Component } from "react";
    import { BrowserRouter as Router, Switch } from "react-router-dom";
    import FrontendAuth from "./FrontendAuth";
    import routerMap from "./routerMap";
    class App extends Component {
      // eslint-disable-next-line no-useless-constructor
      constructor(props) {
        super(props);
      }
      render() {
        return (
          <Router>
            <div>
              <Switch>
                <FrontendAuth routerConfig={routerMap} />
              </Switch>
            </div>
          </Router>
        );
      }
    }
     
    export default App;
    

     所有的路由跳转,都交给 FrontendAuth 高阶组件代理完成。下面是 FrontendAuth 组件的实现:

    //FrontendAuth.js
    import React, { Component } from "react";
    import { Route, Redirect } from "react-router-dom";
    class FrontendAuth extends Component {
      // eslint-disable-next-line no-useless-constructor
      constructor(props) {
        super(props);
      }
      render() {
        const { routerConfig, location } = this.props;
        const { pathname } = location;
        const isLogin = sessionStorage.getItem("username");
        console.log(pathname, isLogin);
        console.log(location);
        // 如果该路由不用进行权限校验,登录状态下登陆页除外
        // 因为登陆后,无法跳转到登陆页
        // 这部分代码,是为了在非登陆状态下,访问不需要权限校验的路由
        const targetRouterConfig = routerConfig.find(
          (item) => item.path === pathname
        );
        console.log(targetRouterConfig);
        if (targetRouterConfig && !targetRouterConfig.auth && !isLogin) {
          const { component } = targetRouterConfig;
          return <Route exact path={pathname} component={component} />;
        }
        if (isLogin) {
          // 如果是登陆状态,想要跳转到登陆,重定向到主页
          if (pathname === "/login") {
            return <Redirect to="/" />;
          } else {
            // 如果路由合法,就跳转到相应的路由
            if (targetRouterConfig) {
              return (
                <Route path={pathname} component={targetRouterConfig.component} />
              );
            } else {
              // 如果路由不合法,重定向到 404 页面
              return <Redirect to="/404" />;
            }
          }
        } else {
          // 非登陆状态下,当路由合法时且需要权限校验时,跳转到登陆页面,要求登陆
          if (targetRouterConfig && targetRouterConfig.auth) {
            return <Redirect to="/login" />;
          } else {
            // 非登陆状态下,路由不合法时,重定向至 404
            return <Redirect to="/404" />;
          }
        }
      }
    }
    export default FrontendAuth;
    

     创建登录的界面src/page/login.js,代码如下:

    import React, { Component } from "react";
    import { Redirect } from "react-router-dom"; //重定向使用
    class Login extends Component {
      constructor(props) {
        super(props);
        this.state = {
          username: "",
          password: "",
          rediectToReferrer: false, // 是否重定向之前的界面
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSumit = this.handleSumit.bind(this);
      }
      // 处理用户名、密码的变化
      handleChange(e) {
        if (e.target.name === "username") {
          this.setState({
            username: e.target.value,
          });
        } else if (e.target.name === "password") {
          this.setState({
            password: e.target.value,
          });
        }
      }
      // 提交登录表单
      async handleSumit(e) {
        e.preventDefault();
        const username = this.state.username;
        const password = this.state.password;
        if (username.length === 0 || password.length === 0) {
          alert("用户名或密码不能为空!");
          return;
        }
        // 保存信息到sessionStorage
        sessionStorage.setItem("username", username);
        // 登录成功后,设置redirectToReferrer为true;
        this.setState({
          rediectToReferrer: true,
        });
        let RedirectUrl = this.props.location.state
          ? this.props.location.state.from.pathname
          : "/";
        // 登陆成功之后的跳转
        this.props.history.push(RedirectUrl);
      }
      render() {
        return (
          <form className="login" onSubmit={this.handleSumit}>
            <div>
              <label htmlFor="">
                用户名:
                <input
                  type="text"
                  name="username"
                  value={this.state.username}
                  onChange={this.handleChange}
                />
              </label>
            </div>
            <div>
              <label htmlFor="">
                密码:
                <input
                  type="password"
                  name="password"
                  value={this.state.password}
                  onChange={this.handleChange}
                />
              </label>
            </div>
            <input type="submit" value="登录" />
          </form>
        );
      }
    }
    export default Login;
    

     

    页面上的路由跳转,都由 FrontendAuth 高阶组件代理了,在 Switch 组件内部,不再是 Route 组件,而只有一个 FrontendAuth 组件。
    FrontendAuth 组件接收一个名为 config 的 Props,这是一份路由表。同时,由于 FrontendAuth 组件放在了 Switch 组件内部,React Router 还自动为 FrontendAuth 注入了 location 属性,当地址栏的路由发生变化时,就会触发 location 属性对象上的 pathname 属性发生变化,从而触发 FrontendAuth 的更新(调用 render 函数)。
    FrontendAuth 的 render 函数中,根据 pathname 查找到路由表中的相关配置,如果该配置中指定了无需校验,就直接返回相应的 Route 组件。
    如果查找到的配置需要进行校验,再根据是否登陆进行处理,具体可以查看代码中的注释。

    总结一下,实现路由守卫需要考虑到以下的问题:

    1. 未登录情况下,访问不需要权限校验的合法页面:允许访问
    2. 登陆情况下,访问登陆页面:禁止访问,跳转至主页
    3. 登陆情况下,访问除登陆页以外的合法页面:允许访问
    4. 登陆情况下,访问所有的非法页面:禁止访问,跳转至 404
    5. 未登录情况下,访问需要权限校验的页面:禁止访问,跳转至登陆页
    6. 未登录情况下,访问所有的非法页面:禁止访问,跳转至 404

     互联网收集整合实际


     

  • 相关阅读:
    解决document.execCommand执行fontSize不能超过48px的问题
    JS实现值复制
    DGIS之遥感影像数据获取
    Chrome获取微信授权,调试公众号页面
    【Three.js】如何选中外部模型
    【Three.js】模型抗锯齿处理
    【Three.js】实现随心所欲的展示外部三维模型
    【GIS新探索】算法实现在不规则区域内均匀分布点
    WebGIS简单实现一个区域炫酷的3D立体地图效果
    【GIS新探索】GeoHash原理和编解码实现
  • 原文地址:https://www.cnblogs.com/lllomh/p/14991885.html
Copyright © 2020-2023  润新知