- 不同的路径渲染不同的组件
- 有两种实现方式
- HashRouter:利用hash实现路由切换
- BrowserRouter: 利用h5 Api实现路由的切换
h5中的路由
hash
默认地址栏后面会加hash,如 http://www.a.com/index.html#
hash 模式 前端路由的特点,不刷新,但是可以根据路径显示不同的内容
hash 不是浏览器的规范,优点:兼容性比较好,缺点是不美观 (#/…)
1 | <a href="#/home">首页</a> |
点击a标签,可以看到路由变化了,但是页面没有改变
1 | 1)初始化路径 |
2)监听
根据路径渲染div里面的内容
1 | container.innerHTML = window.location.hash; |
history
window.history
window.history.pushState({},null,’/‘)
默认我们的h5 history api 它不支持强制刷新,会找不到对应的路径(比如当前是/页面,通过window.history.pushState({},null,’/user’),路由改变为/user,这时候刷新,页面会显示 Cannot GET /user)
如果页面找不到对应的路径,可以跳转到首页,在通过window.history.pushState跳到这个/user页面上
1 | <a onclick="push('/')">首页</a> |
点击a标签可以看到页面和路径都变化,且浏览器最上角的前进后退按钮历史数据一直在叠加,可以通过window.history.length看到
1)默认前进、后退是不会调用pushState方法的
1 | window.addEventListener('popstate',function(){ // 只有在点击[前进][后退]按钮时才触发 |
React中的路由
HashRouter | BrowserRouter
npm install –save react-router-dom
使用
1 | import React from 'react'; |
实现
Router提供属性和方法,父组件提供,子组件(Route)拿
在Home组件中打印
1 | render() { |
打印如下:
这里的 history、location 不是原生windows上的,是自己封装的 math指匹配到的信息:路径、路径参数、是否是精确匹配
步骤
1) HashRouter 要提供一个对象 history location match, 传递给后代组件 ,更新视图(setState)
2) Route 路由 主要的工作是拿到父组件中路径 和自己身上的path比较是否相等,如果相等渲染自己的component即可
1.
index.js
1 | import {HashRouter as Router, Route} from './react-router-dom'; |
新建 ./src/react-router-dom/index.js
1 | import HashRouter from './HashRouter'; |
新建 ./src/react-router-dom/HashRouter.js
1 | import React, { Component } from 'react'; |
父组件提供值
新建 ./src/react-router-dom/Route.js
1 | import React, { Component } from 'react'; |
子组件拿到值去匹配
新建 ./src/react-router-dom/context.js
1 | // 提供一个上下文环境 |
2.
HashRouter.js
1 | import React, { Component } from 'react'; |
Route.js
1 | import React, { Component } from 'react'; |
浏览器地址改为 http://localhost:3000/#/user console.log输出: 3个location的对象和/user
3.
在Route中匹配组件
1 | import React, { Component } from 'react'; |
将地址栏地址改为http://localhost:3000/#/user | http://localhost:3000/#/ | http://localhost:3000/#/profile 都能匹配到相应的组件
4. Link
4.1 原生
index.js
1 | import React from 'react'; |
这里Link在页面上hash路由解析成如下:
1 | <nav> |
4.2 手写
新建./src/react-router-dom/Link.js
1 | import React from 'react'; |
HashRouter.js
1 | import React, { Component } from 'react'; |
5. exact
5.1 path-to-regexp
将路径转化为正则
这个包react默认引用,不用安装
1 | // 将路径转化成正则 |
5.2
Route.js
1 | import React, { Component } from 'react'; |
6. Switch
这里使用原生的,当如下:
1 | <Route path="/" exact={false} component={Home} /> |
这里匹配到一个/user之后会继续向下匹配,当有多个匹配成功则页面上显示多个组件,使用 Switch之后
1 | import {HashRouter as Router, Route, Link, Switch} from 'react-router-dom'; |
只匹配一次,匹配到了就不走下面了
6.1 手写
新建 ./src/react-router-dom/Switch.js
1 | // 循环所有的孩子,如果一个路径匹配到就停止循环 |
7. Redirect
当路径匹配不到就重定向到首页
1 | import {HashRouter as Router, Route, Link, Switch, Redirect} from 'react-router-dom'; |
注意,这里Redirect必须要和Switch一起使用,不然导致死循环,因为/ 会一直向下匹配
7.1 手写
新建./src/react-router-dom/Redirect.js
1 | import React, { Component } from 'react'; |
8. render
Route进行渲染的时候,有三种方式:
1、 第一种是Component
2、 第二种是render,会渲染render这个函数返回的内容
3、第三种是children
权限判断,如果没有登录就去登录页面
index.js
1 | <Switch> |
新建 ./src/pages/Protected.js
1 | import React from 'react'; |
Route.js
1 | let props = { |
新建 ./src/pages/Login.js
1 | import React, { Component } from 'react' |
9. withRouter
把一个组件当成Route渲染出来,具有Route上的属性(history,location…等)
新建./src/react-router-dom/withRouter.js
1 | import {Route} from '../react-router-dom'; |
新建一个NavHeader.js组件
1 | import React, { Component } from 'react' |
10. BrowserRouter
BrowserRouter 用的history对象来实现, history.pushState()
新建./src/react-router-dom/BrowserRouter.js
1 | import React, { Component } from 'react' |