:::info 前端路由的演化顺序与阶段:
- 后端路由阶段
- 前后端分离阶段(ajax阶段)
- 单页应用程序-SPA
前端路由模式:
- hash模式
- history模式
前端路由的底层原理:
- 通过改变url,但是页面不进行刷新(a标签不行、使用a标签页面会自动刷新)。
- 通过url路径上的hash值来改变url,页面不会进行刷新操作(底层原理是监听浏览器的hashchange事件)。
- 通过html5中的history模式修改url,页面也不会进行刷新。
- 原理:监听路径url的改变,并且在路径改变之后切换到不同的页面。在进行页面切换的时候、请求不同的数据。从而达到不刷新页面的情况下,更新界面。 :::
1 hash路由模式的使用
// hash路由模式的使用
<body>
<div class="app">
<a href="#/home">首页</a>
<a href="#/about">关于</a>
</div>
<div class="router-view"></div>
<script>
// 获取dom元素
const content = document.getElementsByClassName("router-view")[0];
// 监听事件
window.addEventListener('hashchange', () => {
// 根据不同的路径 进行内容也的更换
switch (location.hash) {
case "#/home":
content.innerHTML = "首页";
break;
case "#/about":
content.innerHTML = "关于";
break;
default:
content.innerHTML = ""
}
})
</script>
</body>
// 使用hash模式的时候 本质上就是使用浏览器来监听hashchange事件 第三方库的本质就是hashchange事件的改变,不同的路径更换不同的内容,在我们的单页面开发中,我们就是不同组件之间的相互切换。这就是路由切换的底层原理。
2 history路由模式的使用
:::info 使用的html5的history模式 history接口是html5新增的 它有6种模式在改变url的情况下而不刷新页面。
- replaceState() 替换原来的路径
- pushState() 前进,当前的路径向前
- popState() 后退,当前的路径向后退
- go() 随意切换路径 传入相应的参数 向前或者向后改变路径 例如go(-1)、go(2)
- forward() 路径向前 向前改变路径
back() 路径后退 向后改变路径 :::
// history路由模式的演示
<body>
<div class="app">
<a href="/home">首页</a>
<a href="/about">关于</a>
</div>
<div class="router-view"></div>
<script>
const aElements = document.getElementsByTagName("a");
const routerViewElement = document.getElementsByClassName("router-view")[0];
// 对数据进行循环遍历
for(let item of aElements) {
item.addEventListener('click', (e) => {
// 阻止a标签的默认事件
e.preventDefault();
const href = item.getAttribute("href");
// 进行路由的切换
history.pushState({}, "", href);
// 调用函数
urlChange();
})
}
// 浏览器的前进与后退执行的popstate的操作 我们可以监听这个函数的改变
window.addEventListener('popstate', urlChange);
// 定义url的改变
function urlChange() {
switch(location.pathname) {
case "/home":
routerViewElement.innerHTML = "首页";
break;
case "/about":
routerViewElement.innerHTML = "关于";
break;
default:
routerViewElement = "";
}
}
</script>
</body>
3 react-router的基本介绍
:::info 注意事项:
从React router4开始 路由不再集中在一个包中进行管理了。react-router是router的核心部分代码
- react-router-dom是用于浏览器的
- react-router-native是用于原声运用的
目前使用最新的React Router版本是V5的版本 实际上v4的版本与v5的版本差异并不大
react-router的基本原理:
- 路由的模式 HashRouter或者BrowserRouter包含了对路由路径改变的监听 并且会将相应的路径传递给子组件。
- hash模式
- 使用HashRouter组件对要整个应用程序进行包裹。
- 将HashRouter映射为组件的形式。
- history模式
- 使用BrowserRouter组件对整个应用程序包裹。
- 直接将BrowserRouter映射为组件标签的形式。
- hash模式
- 导航的标签 Link组件标签与NavLink组件标签
- 通常路径的跳转是使用Link组件,在Link组件的的to属性上写上需要跳转的路径。最终会渲染成为a标签。
- NavLink标签是在Link标签的基础上增加了一些样式属性。
- to属性是Link组件中最重要的属性,用于设置跳转的路径。
- Route 组件具体的切换,相当于使用的是组件的占位符
- Route组件—用于路径的匹配。
- path属性—用于设置匹配到的路径。
- component属性—设置匹配到路径后,渲染的组件。
- exact—精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件。
:::
// 安装react-router
// 安装react-router-dom会自动帮助我们安装react-router的依赖。
yanr add react-router-dom
// react-router-dom包的内部会需要依赖react-router包,所有我们不需要单独的安装react-router包。原因是更加方便的管理,我们所有路由中需要使用的组件或者api可以统一从react-router-dom进行到处,统一管理,更加方便。
4 react-router-dom的基本使用
```javascript // 引入路由相关的组件 HashRouter // import { HashRouter, Link, Route } from “react-router-dom”;
// 使用history模式 import { BrowserRouter, Link, Route } from “react-router-dom”;
import Home from “./views/Home”; import About from “./views/About”; import Profile from “./views/Profile”;
function App() { return (
{/* 路由展示区域 */}
<Route exact path='/' component={Home}/>
<Route path="/about" component={About}></Route>
<Route path='/profile' component={Profile}/>
</BrowserRouter>
</div>
); }
export default App;
<a name="eWEtW"></a>
# 5 Link组件、NavLink组件的使用
:::info
从react-router-dom中引入Link组件、NavLink组件<br />import { Nav, NavLink } from "react-router-dom";<br />导航组件的本质就是封装的a标签,同时阻止a标签的模式事件,与用户进行交互、实现不刷新页面的情况下,实现路由更新、组件更新、洁面更新。<br />NavLink组件标签的特点:
- activeStyle--在组件激活时展示的样式,需要设置在每一个组件标签上,可以设置选中时的样式。
- activeClassName--活跃时添加的class样式。
- exact--是否精准匹配路径。
总结:NavLink标签组件比Link组件更加灵活、可使用组件预留的样式或者相应的类名,还可以进行自定义类名,使用起来是非常方便的。
:::
```javascript
// 导航标签Link的使用
import { Link, NavLink } from "react-router-dom";
// Link使用详情
<Link exact to="/" activeStrle={{ color: "red" }}>首页<Link>
<Link to="/about" activeStrle={{ color: "red" }}>关于<Link>
<Link to="/profile" activeStrle={{ color: "red" }}>我的<Link>
// NavLink的详细使用
<NavLink to="/" activeClassName="link-active">首页<NavLink>
<NavLink to="/about" activeClassName="link-active">关于<NavLink>
<NavLink to="/profile" activeClassName="link-active">我的<NavLink>
6 Switch组件的使用
// 路由区域正常的使用
import { Route } from "react-router-dom";
<Route to="/" component={组件A}>首页<Route>
<Route to="/about" component={组件B}>关于<Route>
<Route to="/profile" component={组件C}>我的<Route>
// 这里使用动态路由
<Route to="/:id" component={组件D}>用户<Route>
// 未匹配到对应的路由 在实际的业务开发中 一般对应404页面
<Route component={组件E}>
// 上述的Router标签就是一个占位符的形式,当浏览器中路径与to属性的路径进行匹配时。就会展示对应的组件,但是存在一个问题。浏览器中的路径与to属性的路径是模糊匹配的关系,可能存在一个路径对应多个组件的关系 这是我们需要使用exact 这个内置属性了。还需要在外层添加Switch组件进行切换。
// 在实际的开发中,Switch组件利用的是一种排他的思想,从上向下匹配组件,当匹配到第一个组件后,就不会再匹配其他的组件了。我们Switch组件将所有的Route包裹即可。
// Switch组件的使用
<Switch>
<Route exact to="/" component={...}>首页<Route>
<Route to="/about" component={...}>关于<Route>
<Route to="/profile" component={...}>我的<Route>
<Route to="/:id" component={...}>用户<Route>
<Route component={...}>
<Switch>
7 Redirect组件
:::info Redirect用于路由的重定向。当使用这个Redirect组件的时候,就会执行跳转到to属性对应的路径中去。 :::
// 案例演示 根据组件内部的状态进行鉴权 是否有权限查看某个页面。
class Demo extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
isLogin: true
}
}
render() {
return (
{
this.state.isLogin ? "欢迎回来" :<Redirect to="/login" />
}
)
}
}
8 嵌套路由使用
:::info 嵌套路由在日常的开发中使用是非常常见的。其实原理很简单就是在需要使用路由的地方写好路由表,在父组件中写好路由表,然后引入子组件,子组件Router的to属性会与浏览器的url进行路径的匹配,当路径匹配正确后,就会展示相应的字组件,这就是嵌套路由的实现。 :::
9 手动跳转路由
:::info 手动跳转路由有两种方式:通过javascript来进行路由跳转的前提,必须要获取history对象。
- 如果组件是通过路由跳转过来的,也就是说在组件的外部包裹了一层Router组件,那么它将会默认将路由的history、location等属性传递过来。我们在组件的props属性中可以直接获取,可以直接使用this.props.history.push(“/home”)等方式来进行路由的跳转。
- 如果改组件是一个普通渲染的组件,是无法获取history、location、match对象的。
- 如果希望我们的普通App组件获取history属性的话,需要满足下面这个条件
- App组件必须包裹在router组件之内。
- App组件使用WithRouter高阶组件进行包裹。 ::: ```javascript // 使用路由组件对整个应用程序进行包裹 import { HashRouter } from “react-router-dom”;
- 如果希望我们的普通App组件获取history属性的话,需要满足下面这个条件
// index.js 整个应用程序的根组件 import React from ‘react’; import ReactDOM from ‘react-dom’; import App from ‘./App’;
ReactDOM.render(
// 对整个应用程序的根组件 使用路由组件进行包裹
// App根组件中的渲染函数 function App(props) { // 在这里就可以获取到路由的相关属性了 const history = props.history; console.log(history);
handleJump() { // 利用history即可 传入相对应的路径 history.push(“/login”) }
retrun (
<div>
我是App组件
<button onClick={() => this.handleJump() }>手动跳转路由</button>
</div>
) }
// 使用WithRouter高阶组件进行包裹 export default WithRouter(App);
<a name="u4oVZ"></a>
# 10 动态路由的使用
:::info
动态路由指的是路由的路径中某一部分的内容是固定的,其中还有一部分的值是动态,前端对路径进行解析的时候,可以根据动态参数的不同发送不同的网络请求,获取不同的数据,达到动态展示的效果,这就是动态路由。动态路由可以携带相应的参数。
:::
<a name="xjC7b"></a>
# 11 参数的传递
:::info
react-router中参数的传递有三种方式:
- 使用动态路由来传递参数。
- 使用search来传递参数-在路径的后面跟上需要搜索的search参数。
- 使用to属性的时候、to属性可以传递一个对象,将需要传递的参数放置于对象中。
:::
```javascript
// 1. 使用动态路由的形式传递参数
在路由的路径中,/detail路径对应的是Detail详情组件。我们将Route中的路径写为"/detail/:id"。那么路径"/detail/abc"或者"/detail/123"都将匹配到该route,并且进行显示。
这种匹配规则,我们称之为动态路由。通常情况下我们使用动态路由可以通过路由传递参数。
// 动态路由的使用
import { NavLink } from "react-router-dom";
<NavLink to="/detail/abc123">商品详情<NavLink>
// 在业务组件使用props.match来获取传递的参数
// 2. 使用search路径查询部分传递参数
import { NavLink } from "react-router-dom";
<NavLink to="/detail?name=coderweiwei&age=18">详情2<NavLink>
在业务组件中使用props.location在location中获取传递的参数 参数在search属性上面
// 3. 使用Link或者NavLink组件的to属性可传递一个对象,将需要传递的参数放置于对象中。
import { NavLink } from "react-router-dom";
<NavLink to={{
pathname: "/detail", // 需要导航的路径
search: "?name=coder&age=123" // 查询的参数键值对
hash: "document", // hash值 一般使用hashRouter时会使用
state: { height: 190, weight: 120 }, // 传递的任意参数都是可以放入到state中
}}>查看详情
</NavLink>
// 在业务组件中使用props.location在location中获取传递的参数 所有的属性都在location对象中
// 上述各种传参的形式 在对应的业务组件中都是可以获取到的 一般在props属性中。