React 路由 系统管理员 2022-10-07 08:51 153阅读 0赞 ## React 路由 ## [尚硅谷 2021 版 React 技术全家桶全套完整版(零基础入门到精通/男神天禹老师亲授)][2021 _ React] ### 路由 SPA ### 1. 单页 Web 应用(Single Page Web Application) 2. 整个应用只有**一个完整的页面** 3. 点击页面中的链接**不会刷新页面**,只会做页面的**局部更新** 4. 数据都需要通过 ajax 请求获取,并在前端异步展现 **1. 什么是路由** 1. 一个路由就是一个映射关系(key:value) 2. key 为路径,value 可能是 function 或 component **2. 路由分类** 1. 后端路由 * 理解:value 是 function,用来处理客户端提交的请求 * 注册路由:`router.get(path, function(req, res))` * 工作过程:当 node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据 2. 前端路由 * 理解:value 是 component,用于展示页面内容 * 注册路由:`<Route path="/test" component={Test}>` * 工作流程:当浏览器的 path 变为 `/test` 时,当前路由组件就会变为 Test 组件 <a href="http://www.baidu.com" onclick="return push('/test1') ">push test1</a><br /><br /> <button onClick="push('/test2')">push test2</button><br /><br /> <button onClick="replace('/test3')">replace test3</button><br /><br /> <button onClick="back()"><= 回退</button> <button onClick="forword()">前进 =></button> <script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script> <script type="text/javascript"> // let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API let history = History.createHashHistory() //方法二,hash值(锚点) function push(path) { history.push(path) return false } function replace(path) { history.replace(path) } function back() { history.goBack() } function forword() { history.goForward() } history.listen(location => { console.log('请求路由路径变化了', location) }) </script> 样式丢失问题: 1. public/index.html 中引入样式时不写 `./` 写 `/` (常用) 2. public/index.html 中引入样式时不写 `./` 写 `%PUBLIC_URL%` (常用) 3. 使用 HashRouter <link rel="stylesheet" href="./bootstrap.css" /> <!-- 1.去掉. --> <link rel="stylesheet" href="/bootstrap.css" /> <!-- 2.使用%PUBLIC_URL% --> <link rel="stylesheet" href="%PUBLIC_URL%/bootstrap.css" /> <!-- 3.把BrowserRouter改为HashRouter --> <BrowserRouter> <App /> </BrowserRouter> <HashRouter> <App /> </HashRouter> ### 路由基本使用 ### react-router-dom 1. react 的一个插件库 2. 专门用来实现一个 SPA 应用 3. 基于 react 的项目基本都会用到此库 [https://react-router.docschina.org/][https_react-router.docschina.org] 基本使用: 1. 明确界面中的导航区、展示区 2. 导航区 a 标签改为 Link 标签 `<Link to="/xxx">Demo</Link>` 3. 展示区写 Route 标签进行路径的匹配 `<Route path="/xxx" component={Demo}>` 4. `<App />` 最外侧包裹一个 `<BrowserRouter />` 或 `<HashRouter />` {/* 原生html中,靠<a>跳转不同的页面 */} {/* <a className="list-group-item active" href="./about.html"> About </a> <a className="list-group-item" href="./home.html"> Home </a> */} {/* 在React中靠路由链接实现切换组件-编写路由链接 */} <Link className="list-group-item" to="/about"> About </Link> <Link className="list-group-item" to="/home"> Home </Link> {/* 注册路由 */} <Route path="/about" component={About} /> <Route path="/home" component={Home} /> 路由组件与一般组件区别: 1. 写法不同: 一般组件:`<Demo />` 路由组件:`<Route path="/demo" component={Demo} />` 2. 存放位置不同: 一般组件:components 路由组件:pages 3. 接收到的 props 不同: 一般组件:写组件标签时传递了什么,就能收到什么 路由组件:接收到三个固定属性 `history`、`location`、`match` history: go: ƒ go(n) goBack: ƒ goBack() goForward: ƒ goForward() push: ƒ push(path, state) replace: ƒ replace(path, state) location: pathname: "/about" search: "" state: undefined match: params: { } path: "/about" url: "/about" ### NavLink 基本使用 ### 1. NavLink 可以实现路由链接的高亮,通过 `activeClassName` 指定样式名 2. 标签体内容是一个特殊的标签属性 3. 通过 `this.props.children` 可以获取标签体内容 `{...this.props}` 不仅可以把在内联标签属性添加过来,还能把标签体的内容(children)拿过来填写在标签体内部 import React, { Component } from 'react' import { NavLink } from 'react-router-dom' export default class MyNavLink extends Component { render() { return <NavLink activeClassName="active" className="list-group-item" {...this.props} /> } } // 组件调用 <MyNavLink to="/about">About</MyNavLink> ### Switch 基本使用 ### 1. 通常情况下,path 和 component 是一一对应的关系 2. Switch 可以提高路由匹配效率(单一匹配) <Switch> <Route path="/about" component={About} /> <Route path="/home" component={Home} /> <Route path="/home" component={About} /> </Switch> ### 嵌套路由(匹配 重定向) ### **模糊匹配** * `to="/home/a/b"` 可以匹配上 `path="/home"` <MyNavLink to="/about">About</MyNavLink> <MyNavLink to="/home/a/b">Home</MyNavLink> <Switch> <Route path="/about" component={About} /> <Route path="/home" component={Home} /> </Switch> 1. 默认使用的是模糊匹配(【输入的路径】必要要包含【匹配的路径】,且顺序要一致) 2. 开启严格匹配 `<Route exact path="/about" component={About} />` 3. **严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由** **重定向** * 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到 Redirect 指定的路由 <Switch> <Route path="/about" component={About} /> <Route path="/home" component={Home} /> <Redirect to="/about" /> </Switch> **嵌套路由** 1. 注册子路由时要写上父路由的 path 值 2. 路由的匹配时按照注册路由的顺序进行的 <MyNavLink to="/home/news">News</MyNavLink> <MyNavLink to="/home/message">Message</MyNavLink> <Switch> <Route path="/home/news" component={News} /> <Route path="/home/message" component={Message} /> <Redirect to="/home/news" /> </Switch> ### 向路由组件传递参数 ### state = { messageArr: [ { id: '01', title: '消息1' }, { id: '02', title: '消息2' }, { id: '03', title: '消息3' }, ], } <ul> {messageArr.map(msgObj => { return ( <li key={msgObj.id}> <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> </li> ) })} </ul> 1. params 参数 路由链接(携带参数):`<Link to="/demo/test/tom/18">详情</Link>` 注册路由(声明接收):`<Route path="/demo/test/:name/:age" component={Test} />` 接收参数:`const {name, age} = this.props.match.params` {/* 向路由组件传递params参数 */} <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> {/* 声明接收params参数 */} <Route path="/home/message/detail/:id/:title" component={Detail} /> // 接收params参数 const { id, title } = this.props.match.params 1. search 参数 路由链接(携带参数):`<Link to="/demo/test?name=tom&age=18">详情</Link>` 注册路由(无需声明,正常注册即可):`<Route path="/demo/test" component={Test} />` 接收参数:`const {search} = this.props.location; const {name, age} = qs.parse(search.slice(1))` 备注:获取到的 search 是 urlencoded 编码字符串,需要借助 querystring 解析 {/* 向路由组件传递search参数 */} <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> {/* search参数无需声明接收 */} <Route path="/home/message/detail" component={Detail} /> // 接收search参数 const { search } = this.props.location const { id, title } = qs.parse(search.slice(1)) 1. state 参数 路由链接(携带参数):`<Link to={ {path:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>` 注册路由(无需声明,正常注册即可):`<Route path="/demo/test" component={Test} />` 接收参数:`const {name, age} = this.props.location.state` 备注:刷新也可以保留住参数 {/* 向路由组件传递state参数 */} <Link to={ { pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link> {/* state参数无需声明接收 */} <Route path="/home/message/detail" component={Detail} /> // 接收state参数 const { id, title } = this.props.location.state || {} ### 编程式路由导航 ### 默认是 push 模式 <MyNavLink to="/home/news">News</MyNavLink> <MyNavLink replace to="/home/message">Message</MyNavLink> 借助 `this.props.history` 对象上的 API 对操作路由跳转、前进、后退 * `this.props.history.push()` * `this.props.history.replace()` * `this.props.history.gpBack()` * `this.props.history.goForward()` * `this.props.history.go()` import React, { Component } from 'react' import { Link, Route } from 'react-router-dom' import Detail from './Detail' export default class Message extends Component { state = { messageArr: [ { id: '01', title: '消息1' }, { id: '02', title: '消息2' }, { id: '03', title: '消息3' }, ], } replaceShow = (id, title) => { // replace跳转+携带params参数 // this.props.history.replace(`/home/message/detail/${id}/${title}`) // replace跳转+携带search参数 // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`) // replace跳转+携带state参数 this.props.history.replace(`/home/message/detail`, { id, title }) } pushShow = (id, title) => { // push跳转+携带params参数 // this.props.history.push(`/home/message/detail/${id}/${title}`) // push跳转+携带search参数 // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`) // push跳转+携带state参数 this.props.history.push(`/home/message/detail`, { id, title }) } render() { const { messageArr } = this.state return ( <div> <ul> {messageArr.map(msgObj => { return ( <li key={msgObj.id}> {/* 向路由组件传递params参数 */} <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> {/* 向路由组件传递search参数 */} {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */} {/* 向路由组件传递state参数 */} {/* <Link to={ { pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link> */} <button onClick={() => { this.pushShow(msgObj.id, msgObj.title) }} > push操作 </button> <button onClick={() => { this.replaceShow(msgObj.id, msgObj.title) }} > replace操作 </button> </li> ) })} </ul> <hr /> {/* 声明接收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} /> </div> ) } } ### withRouter ### * withRouter 可以加工一般组件,让一般组件具备路由组件所特有的API * withRouter 的返回值是一个新组件 import React, { Component } from 'react' import { withRouter } from 'react-router-dom' class Header extends Component { } export default withRouter(Header) ### BrowerRouter 与 HashRouter 的区别 ### 1. 底层原理不一样 BrowerRouter 使用的是 H5 的 history API,不兼容 IE9 以下版本 HashRouter 使用的是 URL 哈希值 2. path 表现形式不一样 BrowerRouter 的路径中没有 \#,例如:`localhost:3000/demo/test` HashRouter 的路径中包含 \#,例如:`localhost:3000/#/demo/test` 3. 刷新后对路由 state 参数影响 BroserRouter 没有任何影响,因为 state 保存在 history 对象中 HashRouter 刷新后会导致路由 state 参数丢失 4. 备注:HashRouter 可以用于解决一些路径错误相关的问题 [2021 _ React]: https://www.bilibili.com/video/BV1wy4y1D7JT?p=35&spm_id_from=pageDriver [https_react-router.docschina.org]: https://react-router.docschina.org/
还没有评论,来说两句吧...