一、路由
1.1、 SPA的理解
1.单页Web应用(single page web application,SPA)。
2.整个应用只有一个完整的页面。
3.点击页面中的链接不会刷新页面,只会做页面的局部更新。
4.数据都需要通过ajax请求获取, 并在前端异步展现。
1.2、路由的理解
1.什么是路由?
1.一个路由就是一个映射关系(key:value)
2.key为路径, value可能是function或component
2.路由分类
后端路由:
1、理解: value是function, 用来处理客户端提交的请求。
2、注册路由: router.get(path, function(req, res))
3、工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
前端路由:
1、浏览器端路由,value是component,用于展示页面内容。
2、注册路由: <Route path="/test" component={Test}>
3、工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
一、React Router 5
react-router-dom的理解
1、react的一个插件库。
2、专门用来实现一个SPA应用。
3、基于react的项目基本都会用到此库。
下载react-router-dom:
npm install --save react-router-dom
内置组件
1、<BrowserRouter>:用于将应用程序包裹在 HTML5 history API 的 <BrowserRouter> 中,使得 React Router 可以监听 URL 的变化,并且匹配当前 URL 对应的 Route 进行渲染。
2、<HashRouter>:用于将应用程序包裹在 hash history 的 <HashRouter> 中,适用于不支持 HTML5 history API 的环境,如旧版浏览器或一些特殊环境。
3、<Route>:用于声明路由规则,即指定路径对应的组件渲染内容。<Route> 根据当前 URL 路径匹配对应的路径规则,并渲染相关组件。
4、<Redirect>:用于在匹配到某个路径时重定向到另一个路径,可以用于处理一些特殊场景,比如用户访问的旧路径需要重定向到新路径。
5、<Link>:用于在应用中创建导航链接,点击该链接后会更新 URL 而不会重新加载页面,实现单页应用的导航功能。
6、<NavLink>:是 <Link> 的一个增强版本,除了具有 <Link> 的功能外,还可以添加 activeClassName 和 activeStyle 等属性,用于定义链接激活时的样式。
7、<Switch>:用于包裹多个 <Route> 组件,它会遍历所有子 <Route> 组件,并只渲染与当前 URL 匹配的第一个 <Route> 或 <Redirect> 组件,避免多个路由同时匹配的问题
1.1、BrowserRouter 和 HashRouter 的区别
1.底层原理不一样
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。
2.path表现形式不一样
BrowserRouter的路径中没有#,例如: localhost:3000/demo/test
HashRouter的路径包含#,例如: localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中。
(2).HashRouter刷新后会导致路由state参数的丢失!!!
原生html中,靠<a>跳转 不同的页面
<a href="./about.html">About</a>
<a href="./home.html">Home</a>
在React中靠路由链接实现切换组件
首先我们把about.html和home.html改成两个组件
然后引入 Link 和 Route ,通过<Route>注册路由,通过 <Link />进行切换组件
import {HashRouter, Link , Route} from "react-router-dom";
hash路由模式
<HashRouter>
跳转路由
<Link to="/about" />
<Link to="/home" />
注册路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
</HashRouter>
1.2、<NavLink>是<Link>的一个特定版本,会在匹配上当前的url的时候给已经渲染的元素添加参数,组件的属性有:
- activeClassName(string):设置选中样式,默认值为active
- activeStyle(object):当元素被选中时,为此元素添加样式
- exact(bool):为true时,只有当导致和完全匹配class和style才会应用
- strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
- isActive(func)判断链接是否激活的额外逻辑的功能
所以开发中一般使用<NavLink>
路由的基本使用
import { HashRouter, Route, NavLink } from "react-router-dom";
<HashRouter>
跳转路由
<NavLink to="/about" />
<NavLink to="/home" />
注册路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
</HashRouter>
1.3、Switch和Redirect
当我们注册路由,注册了同样的路径,渲染不同的路由组件,当跳转路由的时候有两个路由能匹配上就会出现两个路由组件全部展示的情况,如下图
<Route path="/home" component={Home}></Route>
<Route path="/home" component={Test}></Route>
正常来说一个路径匹配一个路由,上图明显有问题,如果每个同样的路径匹配多个路由组件,如果我们要展示两个路由组件为什么不把两个路由组件合成一个组件呢,当第一个路由组件匹配上以后,如果下面还有无数个相同路径的路由组件,会匹配无数次路由会导致性能损耗,所以一个路径匹配一个路由。这个时候我们会使用Switch:Switch实现提高匹配效率的效果,匹配到第一个后面就不会匹配了
<Switch>
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
<Route path="/home" component={Test}></Route>
一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
<Redirect to="/about" />
</Switch>
路由的严格模式
如上图,我们注册的路由组件路径和跳转路由的开始的路径能匹配上,就能正常展示路由组件的页面,如下图,跳转的路径是 /home/index,注册路由的地址是 /home,因为跳转路径前面的地址是 /home,默认是模糊模式,所以成功匹配展示注册路由组件
如果需要注册的路由组件路径和跳转路由的开始的路径完全一样:
路由开启严格匹配
严格模式不要随便开启,这样会影响二级路由
<Route exact path="/about" component={About}></Route>第一种方法,写exact属性就行
<Route exact={true} path="/home" component={Home}></Route>第二种方法,写exact={true}
嵌套路由
这里是父组件,正常写路由就行
<Switch>
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
<Redirect to="/about" />
</Switch>
这里是子路由的组件,子路由注册的时候需要加上父组件的路径
<Switch>
<Route path="/home/news" component={News}/>//嵌套路由需要加上父路径
<Redirect to="/home/news"/>
</Switch>
React Router 5路由传参
跳转路由
向路由组件传递params参数
<Link to={`/home/message/detail/${i.id}/${i.title}`} children={i.title} />
向路由组件传递search参数
<Link to={`/home/message/detail/?id=${i.id}&title=${i.title}`} children={i.title} />
向路由组件传递state参数
<Link to={{pathname: "/home/message/detail", state: {id:i.id,title:i.title}}} children={i.title} />
注册路由
声明接收params参数
<Route path="/home/message/detail/:id/:title" component={Detail} />
search参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
state参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
路由组件接受路由参数
接收params参数
const {id, title} = this.props.match.params;
接收search参数
import qs from "querystring";
const {id, title} = qs.parse((this.props.location.search).slice(1));
接收state参数
const {id, title} = this.props.location.state || {};
接收search参数,需要下载querystring npm i querystring
querystring基本使用
import qs from "querystring";
let obj = { name: 'tom', age: 18}; //name=tom&age=18 key=value&key=value
console.log(qs.stringify(obj));
let str = 'carName=奔驰&price=199';
console.log(qs.parse(str));
路由跳转模式push和replace
push(/path) 里面的path会进入路由栈,
replace(/path) 不会,但是它里面的path会替换掉路由栈里最后一个路由
路由跳转开启replace模式,默认是push模式
<Link to={`/home/message/detail/${i.id}/${i.title}`} replace={true} children={i.title} />
编程式路由
通过按钮触发方法,方法里进行路由跳转
<button onClick={() => this.pushShow(i)}>Push查看</button>
<button onClick={() => this.replaceShow(i)}>Replace查看</button>
注册路由
接收params参数
<Route path="/home/message/detail/:id/:title" component={Detail} />
search参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
state参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
跳转路由
replaceShow = (i) =>{
replace跳转+携带params参数
this.props.history.replace(`/home/message/detail/${i.id}/${i.title}`)
replace跳转+携带search参数
this.props.history.replace(`/home/message/detail?id=${i.id}&title=${i.title}`)
replace跳转+携带state参数
this.props.history.replace(`/home/message/detail`,{...i})
}
pushShow = (i) =>{
push跳转+携带params参数
this.props.history.push(`/home/message/detail/${i.id}/${i.title}`)
push跳转+携带search参数
this.props.history.push(`/home/message/detail?id=${i.id}&title=${i.title}`)
push跳转+携带state参数
this.props.history.push(`/home/message/detail`,{...i})
}
路由组件接受路由参数
接收params参数
const {id, title} = this.props.match.params;
接收search参数
import qs from "querystring";
const {id, title} = qs.parse((this.props.location.search).slice(1));
接收state参数
const {id, title} = this.props.location.state || {};