1,什么是单页面路由?
路由的本质是监听url的变化,然后匹配路由规则,像是相应的页面,并且无需刷新
2,那什么是路由的原理?
在react-router中,URL对应location对象,而UI是由react components决定的,路由的原理就是实现URL和UI界面的同步,也就是实现location和components之间的同步
3,reactRouter的两种模式
(1)hash模式(HashRouter),
hash模式 | browser模式 | |
url格式 | www.abc.com/#/name | 不带# |
实现 方式 | 当#后面的哈希值发生变化时,不会向服务器请求数据,可以通过hashchange时间来监听URL的变化,从而进行跳转页面 | 使用h5提供的history API(pushState,replaceState和popState事件来保持UI和URL的同步) |
兼容性 | 主要应用在高版本浏览器 | 主要应用在低版本浏览器 |
4,介绍一下history中新增的几个方法
(1)pushState(state,title,url)
作用:在历史记录中新增一条记录,改变浏览器地址栏的url,但是不刷新页面
参数:
* state:一个与添加对象相关联的状态对象,主要用于popState事件,该事件触发时,该对象会传入毁掉函数,换句话意思是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面时,就可以拿到这个对象,如果不需要这个对象的话,可以填null。
*title:新页面的标题,但是呢现在所有浏览器都忽视这个参数,所以也可以填空字符串。
*url:新的网址,但是必须要跟当前网址处在同一个域,浏览器的地址栏里显示的就是这个网址。
eg.假设当前网址是"hello.com/haha.html",使用pushState()方法在浏览器记录中增加一个新纪录
var stateObj={foo:'bar'}
history.pushState(stateObj,'','heihei.html')
history.state //---{foo:"bar"}
需要注意的是,添加新纪录后,浏览器的地址栏会立刻显示'hello/heihei.html',但是不会跳转到‘heihei.htm',也不会检查'heihei.html'是否存在,他只是成为了浏览器历史中的最新纪录。
总之,pushState()方法不会触发页面刷新,只是导致history对象发生变化,地址栏有反应,使用该方法后可以使用history.state属性读出状态对象。
注意:如果pushState的URL参数设置了一个新的hash值,并不会先出发hashChange事件。
(2)replaceState(state,title,url)
作用:替换当前的历史记录,其他的方面跟pushState()方法一模一样。
eg.假定当前的页面是'hello.com/haha.html'。
history.pushState({page:1},'title1','?page=1')
//URL 显示https://hello.com/haha.html?page=1
history.pushState({page:2},'title2','?page=2')
//URL 显示https://hello.com/haha.html?page=2
history.replaceState({page:2},'title3','?page=3')
//URL 显示https://hello.com/haha.html?page=3
history.back()
//URL 显示https://hello.com/haha.html?page=1
history.go(1)
//URL 显示https://hello.com/haha.html?page=3
(3)popState
popState事件是window对象上的事件,配合pushState()和replaceState()方法使用,当同一个网页(不能跳转的那种),的浏览历史出现了变化,就会触发popstate事件。
刚才咱们说了,调用pushState()或者replaceState()方法都会改变当前的历史记录,仅仅调用pushState()或者replaceState()方法并不会触发该事件,触发该事件另外一个条件是用户必须点击浏览器的倒退或者前进按钮,或者说是用js调用history.back()或者history.forward()等方法。
所以总结下popState事件的两个必要触发条件(缺一不可):
--- 1,处在同一个html页面。
--- 2,页面的浏览历史(history对象)发生了改变。
5,browserRouter如何使用
先来是ixanyige最常用的react-router的browser模式。
首先需要create-react-app创建一个项目
接着安装react-router-dom
把没用的东西都删掉,再创建两个组件user和name
export default () => {
const goName=()=>{
props.history.push('/name')
}
return (
<div>
<h2>this is user</h2>
<button onClick={goName}>跳转</button>
</div>
)
};
这是name
export default () => {
return (
<h2>this is user</h2>
)
};
这是index
import React from 'react'
import ReactDOM from 'react-dom';
import {BrowserRouter,Switch,Route} from "react-router-dom"
import User from './page/User'
import Name from './page/Name'
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route path="./" component={User} exact/>
<Route path="./name" components={Name}/>
</Switch>
</BrowserRouter>,
document.getElementById('root')
);
大家可以在自己的电脑上试一下,
先点击跳转到name组件,
再点击浏览器的回退按钮回退到user组件
ok,我们一起来手写一个mini-react-router-dom
这是BrowserRouter.js
import React ,{useEffect,useState,createContext} from 'react'
/*
*@description:1,监听路由变化(popState) 2,页面刷新 3,页面跳转(pushState)-->4,改变path变量
*/
export const RouterContext=createContext();
export const HistoryContext=createContext();
export default function BrowserRouter(props){
// 页面刷新
const [path,setPath]=useState(()=>{
const pathname=window.location.pathname;
return pathname || "/";
})
//改变path
const handlePopState=()=>{
// ui同步
const {pathname}=window.location;
setPath(pathname)
}
// 监听popstate
useEffect(()=>{
// 路由操作
window.addEventListener("popstate",handlePopState);
return ()=>{
window.removeEventListener("popstate",handlePopState)
}
},[]);
const push =(path)=>{
// 路由选择
window.history.pushState({path},null,path);
// ui同步
setPath(path)
}
return(
<RouterContext.Provider value={path}>
<HistoryContext.Provider
value={{push}}
>
{props.children}
</HistoryContext.Provider>
</RouterContext.Provider>
)
}
这是Router
import { useContext } from "react"
import { RouterContext } from "./BrowserRouter"
export default function Route(props) {
const { path: RoutePath, component: RouteComponent } = props
const path = useContext(RouterContext)
return path === RoutePath ? <RouteComponent /> : null
}
这是index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter,Route}from "./mini-router-dom"
import User from './page/User'
import Name from './page/Name'
ReactDOM.render(
<BrowserRouter>
<Route path="./" component={User}/>
<Route path="./name" component={Name}/>
</BrowserRouter>,
document.getElementById('root')
);
这是user。name就不写了,跟上面一样
import {useContext} from "react"
import {HistoryContext} from "./mini-router-dom/BrowserRouter"
export default () => {
const {push}=useContext(HistoryContext)
const goName=()=>{
props.history.push('/name')
}
return (
<div>
<h2>this is user</h2>
<button onClick={goName}>跳转</button>
</div>
)
};
ok,那么这个功能就能完美实现了
希望能够帮到大家~