React router学习
文章目录
1.前端路由实现
1.1 history库
a. 网址: https://github.com/ReactTraining/history
b. 管理浏览器会话历史(history)的工具库
c. 包装的是原生BOM中window.history和window.location.hash
1.2 history API
a. History.createBrowserHistory(): 得到封装window.history的管理对象
b. History.createHashHistory(): 得到封装window.location.hash的管理对象
c. history.push(): 添加一个新的历史记录
d. history.replace(): 用一个新的历史记录替换当前的记录
e. history.goBack(): 回退到上一个历史记录
f. history.goForword(): 前进到下一个历史记录
g. history.listen(function(location){}): 监视历史记录的变化
1.3 源码
history_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>history test</title>
</head>
<body>
<p><input type="text"></p>
<a href="/test1" onclick="return push('/test1')">test1</a><br><br>
<button onClick="push('/test2')">push test2</button><br><br>
<button onClick="back()">回退</button><br><br>
<button onClick="forword()">前进</button><br><br>
<button onClick="replace('/test3')">replace test3</button><br><br>
<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
<script type="text/javascript">
let history = History.createBrowserHistory() // 方式一
history = History.createHashHistory() // 方式二
// console.log(history)
function push (to) {
history.push(to)
return false
}
function back() {
history.goBack()
}
function forword() {
history.goForward()
}
function replace (to) {
history.replace(to)
}
history.listen((location) => {
console.log('请求路由路径变化了', location)
})
</script>
</body>
</html>
2. 相关理解
2.1 react-router的理解
-
react的一个插件库
-
专门用来实现一个SPA应用
-
基于react的项目基本都会用到此库
2.2 SPA的理解
-
单页Web应用(single page web application,SPA)
-
整个应用只有一个完整的页面
-
点击页面中的链接不会刷新页面, 本身也不会向服务器发请求
-
当点击路由链接时, 只会做页面的局部更新
-
**数据都需要通过ajax请求获取, 并在前端异步展现**
2.3 路由的理解
- 什么是路由?
a. 一个路由就是一个映射关系(key:value)
b. key为路由路径, value可能是function/component
- 路由分类
a. 后台路由: node服务器端路由, value是function, 用来处理客户端提交的请求并返回一个响应数据
b. 前台路由: 浏览器端路由, value是component, 当请求的是路由path时, 浏览器端前没有发送http请求, 但界面会更新显示对应的组件
- 后台路由
a. 注册路由: router.get(path, function(req, res))
b. 当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
-
前端路由
a. 注册路由: <Route path="/about" component={About}>
b. 当浏览器的hash变为#about时, 当前路由组件就会变为About组件
3. react-router相关API
3.2 组件
-
<BrowserRouter>
-
<HashRouter>
-
<Route>
-
<Redirect>
-
<Link>
-
<NavLink>
-
<Switch>
3.3 其它
-
history对象
-
match对象
-
withRouter函数
4. 基本路由使用 举例说明
4.1 准备
-
下载react-router: npm install --save react-router-dom
-
引入bootstrap.css: <link rel=“stylesheet” href="/css/bootstrap.css">
4.2 路由组件: views/about.jsx
import React, {Component} from "react";
export default class About extends Component{ //默认暴露,
render() {
return (
<div>
about router component
</div>
)
}
}
4.3 路由组件: views/home.jsx
import React, {Component} from "react";
export default class Home extends Component{ //默认暴露,
render() {
return (
<div>
home router component
</div>
)
}
}
4.4 包装NavLink组件: components/myNavLink.jsx
import React, {Component} from "react";
import {NavLink} from 'react-router-dom'
export default class MyNavLink extends Component{ //默认暴露,
render() {
return (
/*将外部传入的所有属性传递给NavLink*/
<NavLink {...this.props} activeClassName='activeClass'/>
)
}
}
4.5 应用组件: components/app.jsx
import React, {Component} from "react";
import {Route, Switch, Redirect} from 'react-router-dom'
import MyNavLink from './MyNavLink'
import About from '../views/about'
import Home from '../views/home'
export default class App extends Component{ //默认暴露,
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header">
<h2>React Router Demo</h2>
</div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/*导航路由链接*/}
<MyNavLink className="list-group-item" to='/about'>About</MyNavLink>
<MyNavLink className="list-group-item" to='/home'>Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/*可切换的路由组件*/}
<Switch>
<Route path='/about' component={About}/>
<Route path='/home' component={Home}/>
<Redirect to='/about'/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
4.6 自定义样式: index.css
.activeClass {
color: red !important;
}
4.7 入口JS: index.js
import React from "react";
import ReactDOM from 'react-dom'
import {BrowserRouter, HashRouter} from 'react-router-dom'
import App from './components/app'
import './index.css';
ReactDOM.render(
(
<BrowserRouter>
<App/>
</BrowserRouter>
),
document.getElementById('root')
)
;
5. 嵌套路由使用 沿用上例
5.1 如何编写路由组件
- 编写路由组件
- 在父路由中指定:
- 路由链接:如<NavLink>,<Link>,属性为to
- 路由:<Route path>
5.2 二级路由组件: views/news.jsx
import React, {Component} from "react";
export default class News extends Component { //默认暴露,
state = {
newsArray: [
'new1',
'new2',
'new3'
]
}
render() {
return (
<ul>
{
this.state.newsArray.map((news, index) => <li key={index}>{news}</li>)
}
</ul>
)
}
}
5.3 二级路由组件: views/message.jsx
import React, {Component} from "react";
export default class Message extends Component{ //默认暴露,
state = {
messages:[
]
}
componentDidMount() {
//模拟发送ajax请求异步获取数据
setTimeout(()=>{
const messages = [
{id:1,title:'message001'},
{id:2,title:'message002'},
{id:3,title:'message003'}
]
//更新状态
this.setState({messages})
},1000)
}
render() {
return (
<ul>
{
this.state.messages.map((m,index)=>(
<li>
<a href='?'>{m.title}</a>
</li>
))
}
</ul>
)
}
}
5.4 一级路由组件: views/home.jsx
import React, {Component} from "react";
import MyNavLink from "../components/myNavLink";
import {Switch, Route, Redirect} from 'react-router-dom'
import Message from "./message";
import News from "./news";
export default class Home extends Component { //默认暴露,
render() {
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul className = 'nav nav-tabs'>
{/*之前app.jsx路由的to和path可以,但是子路由就要写清楚是home的子路由*/}
{/*可以看看浏览器地址栏路径*/}
<li>
<MyNavLink to="/home/news">News</MyNavLink>
</li>
<li>
<MyNavLink to='/home/message'>Messages</MyNavLink>
</li>
</ul>
<div>
<Switch>
<Route path='/home/news' component={News}/>
<Route path='/home/message' component={Message}/>
<Redirect to='/home/news'/>
</Switch>
</div>
</div>
</div>
)
}
}
6. 向路由组件传递参数数据 沿用上例
6.1 三级路由组件: views/message-detail.jsx
import React from 'react'
const messageDetails = [
{id: '1', title: 'Message001', content: '我爱你, 中国'},
{id: '2', title: 'Message002', content: '我爱你, 老婆'},
{id: '3', title: 'Message003', content: '我爱你, 孩子'},
{id: '4', title: 'Message004', content: '我爱你, 父母'},
]
export default function messageDeatil(props) {
//得到请求参数中的id
//关于这个props.match.params,是从浏览器工具中查到的,基本都是props.match.params.XXX
const {id} = props.match.params
//查询得到对应的message
const message = messageDetails.find((m)=>m.id===id)//返回第一个结果为true的元素
return(
<ul>
<li>ID: {message.id}</li>
<li>TITLE:{message.title} </li>
<li>CONTENT:{message.content} </li>
</ul>
)
}
6.2 二级路由组件: views/message.jsx
import React, {Component} from "react";
import {Route,Link} from 'react-router-dom'
import MessageDetail from "./message-detail"
export default class Message extends Component { //默认暴露,
state = {
messages: []
}
componentDidMount() {
//模拟发送ajax请求异步获取数据
setTimeout(() => {
const messages = [
{id: 1, title: 'message001'},
{id: 2, title: 'message002'},
{id: 3, title: 'message003'},
{id: 4, title: 'message004'}
]
//更新状态
this.setState({messages})
}, 1000)
}
render() {
return (
<div>
<ul>
{
this.state.messages.map((m, index) => (
<li key={index}>
<Link to={`/home/message/messagedetail/${m.id}`}>{m.title}</Link>
</li>
))
}
</ul>
<Route path='/home/message/messagedetail/:id' component={MessageDetail}/>
</div>
)
}
}
7. 多种路由跳转方式
7.1 二级路由: views/message.jsx
import React, {Component} from "react";
import {Route, Link} from 'react-router-dom'
import MessageDetail from "./message-detail"
export default class Message extends Component { //默认暴露,
state = {
messages: []
}
componentDidMount() {
//模拟发送ajax请求异步获取数据
setTimeout(() => {
const messages = [
{id: 1, title: 'message001'},
{id: 2, title: 'message002'},
{id: 3, title: 'message003'},
{id: 4, title: 'message004'}
]
//更新状态
this.setState({messages})
}, 1000)
}
showDetail = (id) => {
this.props.history.push(`/home/message/messagedetail/${id}`)
}
showDetail2 = (id) => {
this.props.history.replace(`/home/message/messagedetail/${id}`)
}
back = () => {
this.props.history.goBack()
}
forward = () => {
this.props.history.goForward()
}
reqpage = ()=>{
//通过js进行页面跳转
window.location = 'https://www.bilibili.com/'
}
render() {
return (
<div>
<ul>
{
this.state.messages.map((m, index) => (
<li key={index}>
<Link to={`/home/message/messagedetail/${m.id}`}>{m.title}</Link>
<button onClick={() => this.showDetail(m.id)}>push查看</button>
<button onClick={() => this.showDetail2(m.id)}>replace查看</button>
</li>
))
}
</ul>
<p>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
</p>
<hr/>
<button onClick={this.reqpage}>页面跳转</button>
<Route path='/home/message/messagedetail/:id' component={MessageDetail}/>
</div>
)
}
}