目录
一、介绍
1、作用:路由是根据不同的url地址展示不同的页面或者内容
2、安装
(1)官网安装:http://reacttraining.com/react-router/web/guides/quick-start
(2)终端安装:
npm install react-router-dom@5
二、使用
1、导入
//引入 import {HashRouter, Router} from 'react-router-dom'
2、定义路由
render(){ return ( <div> <HashRouter> <Router path="/home" component={Home} /> <Router path="/second" component={Second} /> <Router path="/mine" component={Mine} /> </HashRouter> </div> ) }
建议:将路由单独封装在一个js文件中
注意:一级路由与多级路由
3、重定向
作用:如果我们不想让用户访问某个路由或者该路由不在我们书写的路由中,我们可以让组件跳转到我们指定的路由
{/模糊匹配 重定向*/} {/*<Redirect from="/" to="/home" exact />*/} {/*exact 精确地*/} <Redirect path="*" component={Test} />
4、嵌套路由
(1)父组件
<Route path="/home" component={Home}>
(2)子组件Home:直接使用Route
<Route path="/home/page1" component={Page1} /> <Route path="/home/page2" component={Page2} /> <Redirect from='/home' to='home/page1' />
5、路由跳转
(1)声明式路由
<NavLink to="/home" activeClassHome="ok">home</NavLink> <NavLink to="/second" activeClassHome="ok">second</NavLink> <NavLink to="/mine" activeClassHome="ok">mine</NavLink>
(2)编程式路由
<1>this.props.history.push(路由)
<2> props.history.push(路由)
import {useHistory} from 'react-router-dom' const history = useHistory() history.push(路由)
6、路由传参
(1)使用params参数
const index = () => { const arr = [ {id:'001',title:'one'}, {id:'002',title:'two'}, {id:'003',title:'three'}, ] return ( <div> <ul> { arr.map((msg) => ( <li key={msg.id}> {/* 向路由组件传递params参数 */} <Link to={`/home/message/detail/${msg.id}/${msg.title}`}>{msg.title}</Link> </li> )) } </ul> <hr /> {/* 声明接收params参数 */} <Route path='/home/message/detail/:id/:title' component={Detail} /> </div> ) } const index = (props) => { const data = [ {id:'001',text:'第一名'}, {id:'002',text:'第二名'}, {id:'003',text:'第三名'}, ] //接收params参数 const {id, title} = props.match.params const SearchResult = data.find((dataobj) => { return dataobj.id === id; }) return ( <div> <ul> <li>id:{id}</li> <li>title:{title}</li> <li>nm:{SearchResult.text}</li> </ul> </div> ) }
<1>传递params参数
<Link to='/demo/test/001/aa'>展示</Link>
<2>声明接收params参数
<Route path='/demo/test/:id/:title' component='{Test}' />
<3>接收params参数
const {id, title} = props.match.params
(2)使用search参数
const index = () => { const arr = [ {id:'001',title:'one'}, {id:'002',title:'two'}, {id:'003',title:'three'}, ] return ( <div> <ul> { arr.map((msg) => ( <li key={msg.id}> {/* 向路由组件传递search参数 */} <Link to={`/home/message/detail/?id=${msg.id}&title=${msg.title}`}> {msg.title}</Link> </li> )) } </ul> <hr /> <Route path='/home/message/detail' component={Detail} /> </div> ) } const index = (props) => { const detaildata = [ {id:'001',text:'第一名'}, {id:'002',text:'第二名'}, {id:'003',text:'第三名'}, ] //接收search参数 const {search} = props.location const querystring = require('querystringify') const obj = querystring.parse(search.slice(1)) const {id, title} = obj const SearchResult = detaildata.find((dataobj) => { return dataobj.id === id; }) return ( <div> <ul> <li>id:{id}</li> <li>title:{title}</li> <li>nm:{SearchResult.text}</li> </ul> </div> ) }
<1>传递参数
<Link to='/demo/test?id=001&title=aa'>展示</Link>
<2>不用声明接收
<Route path='/demo/test' component='{Test}' />
<3>接收search参数:接收到的数据为字符串形式,需要转换成对象
(3)使用state参数
<1>传递state参数
<Link to={{pathname:'/home/message/detail', state:{id:'001',title:'aa'}}}>展示</Link>
<2>不用声明接收
<Route path='/demo/test/' component='{Test}' />
<3>接收state参数
const {id, title} = props.location.state
注意: 刷新后对路由state参数的影响
<1>BrowserRouter没有任何影响,因为state保存在history对象中。
<2>HashRouter刷新后会导致路由state参数的丢失
7、路由拦截
(1)使用Prompt组件来完成
<1>参数when:boolean型
作用:true弹窗,false顺利跳转。
<2>参数message:function或者字符串
作用:函数返回true就顺利跳转,false停止跳转字符串就弹窗字符串并停止跳转。
注意:当when值为true并且message是函数返回值为false时,才会拦截路由并且不会弹出默认弹出框。
import { Dialog } from '@alifd/meet-react'; import React, { useEffect, useState} from 'react'; import { Prompt, useHistory } from 'react-router'; import style from './index.module.scss'; export default function TestPage() { const history = useHistory(); const [notAllowJump, setNotAllowJump] = useState(true); /** * 路由拦截 * @param {*} location string * @returns boolean */ function handleRouter() { const list = field.getValue('list'); const equal = xxxxx(); // 判断两次值是不是一样 if (equal) { // 两次值一样,用户没改动数据,直接放行 return true; } Dialog.show({ centered: true, content: '是否保存当前修改数据', onOk() { // 用户需要提交,提交后要放行,先将when置为false,再提交操作 setNotAllowJump(false); xxxxxSubmit(); // 继续提交 }, async onCancel() { // 用户不提交,直接放弃修改返回上一页。将when置为false再返回,注意setNotAllowJump操作是异步的。 await setNotAllowJump(false); history.goBack(); }, }); // 用户有修改,返回false拦截跳转,同时屏蔽掉默认弹出框 return false; } return ( <div className={style['test-page']}> <Prompt when={notAllowJump} message={handleRouter} /> <footer> 我是页面内容 </footer> </div> ); }
(2)使用history.block拦截
<1>当返回值为true,路由会跳转,不会弹出默认框。
<2>当返回值为false,路由不会跳转,不会弹出默认框。
<3>当返回值为string,路由不会跳转,会弹出默认框。
注意:当block返回值是false时候,能够拦截路由跳转,并且不会弹出默认提示框。
import { useHistory } from 'react-router'; import { Dialog } from '@alifd/meet-react'; import React, { useEffect, useState} from 'react'; import style from './index.module.scss'; export default function TestPage() { const history = useHistory(); useEffect(() => { history.block(() => { Dialog.show({ centered: true, content: '是否保存当前修改数据', onOk() { history.block(() => true); // 放开拦截提交操作,成功后在提交函数内跳出去 xxxxxSubmit(); }, async onCancel() { history.block(() => true); history.goBack(); }, }); // 开启路由拦截同时阻止默认弹出框 return false; }); }, [history]); return ( <div className={style['test-page']}> <footer> 我是页面内容 </footer> </div> ); }
8、路由模式
(1)HashRouter(哈希路由)
<1>根据URL地址中的哈希值来确定显示的组件(http://localhost:3000/#/first)。
<2>hash的变化,不会导致页面刷新,兼容性较好。
(2)BrowserRouter(浏览器路由)
<1>使用 H5 的 history.pushState API 实现 (http://localhost:3000/first)。
<2>推荐使用浏览器路由。
9、withRouter
(1)作用:可以让一般组件(没有通过component渲染的组件)获取到history属性。
(2)使用方法
<1>在需要使用history属性的组件中引入withRouter(原理:高阶组件)
import {withRouter} from 'react-router-dom'
<2>默认导出
export default withRouter(组件名称)
10、反向代理
(1)解决跨域问题
(2)参考链接:Proxying API Requests in Development | Create React App
(3)开始使用
<1>安装插件:nmp install http-proxy-middleware --save
const {createProxyMiddleware} = require('http-proxy-middleware') module.exports = function (app) { app.use( '/api', createProxyMiddleware({ target:'目标URL', changeOrigin: true } ) ) }
<2>在src文件夹下创建setupProxy.js文件
<3>重新启动app
11、css module
(1)spa应用,在任意js引入css代码都有相当于在head标签内引入,如果是多组件或者多人开发如何避免冲突
(2)我们建议每一个组件都可以放入一个同名文件夹中,这样js与css在一起
(3)css命名时写成 eg. A.module.css
<1>这样这个css样式只对A起作用
<2>注意 :不要单独写 标签名选择器