前端路由实现

245 阅读4分钟

前端路由

什么是前端路由?

通过用户请求的url导航到具体的html页面(url与相应处理程序的影射关系,用户在输入要访问的url之后,路由会解析url中的路径,之后根据映射表中的映射关系查找相应的预设函数,并将结果返回给用户,以此完成一次操作)。路由这个概念最早出现在后端,现在的前端路由不同于传统路由,它不需要服务器解析,而是可以通过 hash 函数或者 history API来实现。在前端开发中,我们可以通过路由设置访问路径,并根据路径与组件的映射关系切换组件的显示,而这整个过程都是在同一个页面中实现的,不涉及页面间的跳转,这也就是我们常说的单页应用(spa)。

前端路由带来了什么

相比多页应用(mpa)来说,spa有以下优点:

  1. 不涉及html页面跳转,内容改变不需要重新加载页面,对服务器压力小。
  2. 只涉及组件之间的切换,因此跳转流畅,用户体验好。
  3. 页面效果会比较炫酷(切换页面内容时的转场动画)。
  4. 组件化开发便捷。 但是同时spa也有以下缺点:
  5. 首屏加载过慢。
  6. 不利于seo。
  7. 页面复杂度提高很多。

前端路由的实现主要有两种,hash和history模式;

hash 实现
  • hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新
  • 通过 hashchange 事件监听 URL 的变化,改变 URL 的方式只有这几种:通过浏览器前进后退改变 URL、通过<a>标签改变 URL、通过window.location改变URL,这几种情况改变 URL 都会触发 hashchange 事件
history 实现
  • history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新
  • history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或<a>标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和<a>标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
以下是用hash实现方式:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>前端路由实现</title>
</head>
<body>
  <ul>
    <li><a href="#/home">首页</a></li>
    <li><a href="#/login">login</a></li>
    <li><a href="#/user">个人中心</a></li>
  </ul>
  <div id="zhangyun"></div>
</body>
<script>
  let view = null;
  window.addEventListener('DOMContentLoaded',onLoad);
  function onLoad(){
    view = document.getElementById('zhangyun');
    onHashChange()
  }
  // 监听 hash 变化
  window.addEventListener('hashchange', onHashChange)
  function onHashChange(){
    switch (location.hash) {
      case '#/home':
        view.innerHTML = '首页';
        break;
      case '#/user':
        view.innerHTML = '个人中心';
        break;
      case '#/login':
        view.innerHTML = '登录';
        break;
    }
  }
</script>
</html>
DOMContentLoaded

MDN的描述是:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完全加载。点这里

react-router

react-router包含3个库,react-router、react-dom和react-native。react-router提供最基本的路由功能,实际使用的时候我们不会直接安装react-router,而是根据应用运行的环境选择安装react-router-dom(在浏览器中使用)或者react-router-native(在rn中使用)。react-router-dom和react-router-native都依赖react-router,所以在安装时,react-router也会自动安装,创建web应用。

安装
npm install --save react-router-dom
BrowserRouter vs HashRouter
  1. HashRouter最简单,不需要服务器端渲染,靠浏览器的 # 来区分path就可以,BrowserRouter需要服务器端对不同的 URL 返回不同的HTML,后端配置可参考
  2. BrowserRouter使用HTML5 history API(pushState,replaceState和popState事件),让页面的UI同步与URL。
  3. HashRouter不支持location.key 和 location.state,动态路由跳转需要通过 ? 传递参数。
  4. Hash history 不需要服务器配置任何配置就可以运行。
MemoryRouter

把URL的历史记录保存在内存中的 (不读取、不写入地址栏)。在测试和非浏览器环境很有用,比如 RN 。

基本使用

react-router中奉⾏⼀切皆组件的思想,路由器-Router、链接-Link、路由-Route、独占-Switch、重 定向-Redirect都以组件形式存在

创建RouterPage.js页面

import React from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";

const RouterPage = () => {
    return (
    <div>
        <Router>
            <Link to="/">首页</Link>
            <Link to="user">个人中心</Link>
            <Route
                exact
                path="/"
                component={HomePage}
            />
            <Route path="/user" component={UserPage} />
        </Router>
    </div>
    )
}

export deafault RouerPage