这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战css
即单页面web(single page web application)
应用。整个应用只有一个完整的页面,点击页面中的连接不会刷新页面,只会作页面的局部更新。数据都须要经过ajax
获取。html
也就是说,正由于有了路由这个技术的存在,才能实现咱们在同一个页面中进行局部刷新(单页面多组件)。前端
一个路由就是一个映射关系(key: value)node
key为路径,value多是function(后端路由) 或 component(前端路由);react
后端路由:注册:router.get(path, function(req, res))
。当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。web
前端路由:注册:Route path="/test" component={Test}
。用于展现页面内容。当浏览器的path变为/test时,当前路由组件就会变成Test组件。好比对于一个在127.0.0.1:3000
的页面,当它为127.0.0.1:3000/home
(而不是/home.html
)显示的就是home组件。ajax
好比下图这个案例,切换的就是页面,而不是组件。(下面会有此案例同个页面多个组件的写法)后端
首先要认识一下react的一个的插件库react-router-dom
(须要手动下载),该库专门用来实现一个SPA应用,基于react的项目基本都会用到它。浏览器
在咱们以前的学习BOM
中,是有一个history方法的,在这里咱们经过引入一个history
的js
文件直接调用历史记录的一些方法。浏览器的历史记录是一个栈的结构。markdown
<script src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
let history = History.createBrowerHistory(); // 直接使用H5推出的history的API
// let history = History.createBrowerHistory(); hash值 锚点跳转(多了个#)
function push(path) {
history.push(path); // 入栈
}
function replace(path) {
history.replace(path); // 替代栈顶元素
}
function back() {
history.goBack(); // 回退
}
function forward() {
history.goForward(); // 前进
}
history.listen(location)=> { // 监听路径变化
console.log(location);
}
复制代码
接下来实现上面那个案例。在原生js
中是经过<a>标签
跳转到不一样的页面,而在react中,是靠路由连接<Link><link/>
实现切换组件的(编写路由连接)。注意:这里的Link
是从react-router-dom
库里面拿的。在组件分别展现的时候须要注册路由route
。
基本步骤:(1)确认界面中的导航区、展现区;(2)导航区的a标签
改成Link标签
;(3)展现区的Route标签进行路径的匹配;(4)在<App>
的最外侧包裹一个<BrowserRouter>
或者<HashRouter>
// App.jsx
import { Link, BrowserRouter, Route } from 'react-router-dom' // 引入react-router-dom库
// 编写路由连接
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
// 注册路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
复制代码
路由在使用的时候,须要在外层中包裹一层<BrowserRouter><BrowserRouter/>
,至关于一个路由器,管理里面的东西。并且只能有一个路由器,不能写2个,不然就至关于两个路由器,两个路由器之间是没有数据沟通的。所以能够在App
组件渲染的时候,在其外层放路由器。即
// index.js
ReactDOM.render(
<BrowserRouter> <App /> </BrowserRouter>,
document.getElementById('root')
);
复制代码
这样子就能够实现一个SPA了。此时能够看到页面路径发生了变化,并且<Link>
标签渲染到浏览器中实际上是转换为<a>
标签的,而to
转换为href
(转换为浏览器认识的标签)。可是是组件的展现而不是页面之间的跳转(没有.html
后缀),打开控制台的network
也能够看到此时的浏览器并无发送请求。
若是想要加上上面那个案例的高亮效果,把Link
改为NavLink
便可(记得从react-router-dom
中引入)。默认点击的时候默认给active
样式,可是若是想要给的样式名不是active
,那就须要加一个activeClassName="..."
(这个的默认值是active)
<NavLink activeClassName="home" className="list-group-item" to="/home">Home</NavLink>
//至关于
<NavLink activeClassName="home" className="list-group-item" to="/home" children="Home"></NavLink>
复制代码
总结:NavLink
能够实现路由连接的高亮,经过activeClassName
指定样式名,标签体内容是一个特殊的标签属性,经过this.props.children
能够获取到标签体内容。
上面这种组件就是路由组件,那么它和普通组件还有什么区别呢?
写法不一样。通常组件:直接写组件标签:<home/>
;
路由组件:<Route path="/about" component={Home}></Route>
存放位置不一样。通常组件放在components
;路由组件通常放在pages
中。
接收到的props
不一样。通常组件:给它传递什么就收到什么;路由组件:接收到3个固定属性
对于路由组件,咱们打印出它的props
属性,这里在用这个组件的时候并无给它传值,可是它会有自带的props
(history
、location
、match
)其中history.location=location
。而对于普通组件,若是没有给它传值,它打印出来的props
就是空的。
上面说的是路由的基础使用,接下来讲一说在路由中是怎么进行组件之间的传参的。
传递params参数
在路由组件传递参数的时候,在Link中传递参数,要在注册的路由将这些参数让Detail接收,采用下面这种方式。此时在Detail组件中打印this.props
的话就能够在this.props.match.params
里面看到咱们经过Link传递过去的参数。
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
<Route path="/home/message/detail/:id/:title" component={Detail}></Route>
复制代码
传递search参数
search参数在传递的时候形式以下。并且search不用在注册路由的时候接收参数,直接注册便可,在this.props.location.search
中就能够找到传递的参数,不过在这里传递的对象是?key=value&key=value
,咱们要手动改为{key: value;}
的形式;
可使用引入内置库import qs from queryString
,再用qs.parse(search)
来处理从this.props
中获得的search
对象(注意:用parse以后前面仍是会有一个?
,用slice(1)
截掉便可
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
复制代码
state参数
上面说的params参数和search参数在传递参数的时候都会将传递的键值对暴露在地址栏上;state和search同样,不用声明接收,直接注册便可;传递参数方式以下(传对象);
传递以后在this.props.location.state
里面就能够找到所传递的参数;注意:路由中的state跟组件中的state是不同的;state参数只是路由中的一个属性,跟组件里面的state的没有关系
<Link to={{pathname='/home/message/detail', state:{id:msgObj.id,title:msgObj.title}}}></Link>
复制代码
用state传递参数的话刷新也能够保留参数。此时虽然参数没有在地址栏,可是也不会丢失,由于在这里用BrowserRouter
来管理路由的,它一直在维护浏览器的history
,history
把传递的东西记下了,所以不会丢失。
home/a/b
时,在找home的路由的时候,会先匹配前面的home,匹配到了就找到了。这就是模糊匹配,且默认就是默认匹配。exact={true}
或exact
来开启严格匹配通常状况下咱们不开启严格匹配,由于有时候开启严格匹配会致使没法继续匹配二级路由
// 编写路由连接 输入的路径
<Link to="/home/a/b">Home</Link>
// 注册路由 匹配的路径
<Route exact={true} path="/home" component={Home}></Route>
复制代码
Switch
组件和Redirect
组件提升效率:Switch
组件。以下代码,经过/home
匹配到Home组件以后就不会继续匹配下去了。不然test组件也会被展现在页面中。注意:要从react-router-dom
中引入Switch
。 Redirect
是react-router-dom
里面的一个内置组件,会让刚刷新浏览器的时候,默认跳转到指定组件。(通常写在全部路由注册的最下方,当全部路由都没法匹配时,跳转到Redirect
指定的路由)
<Switch>
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
<Route path="/home" component={test}></Route>
<Redirect to="/home"/>
</Switch>
复制代码
通常状况下咱们不会让同一个路径去对应展现多个组件,若是出现这种状况的话就可使用Switch
。一般状况下,path和component是一一对应的关系,Switch能够提升路由匹配效率(单一匹配)。
加油!