02_react-router

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的理解

  1. react的一个插件库

  2.    专门用来实现一个SPA应用
    
  3.    基于react的项目基本都会用到此库
    

2.2 SPA的理解

  1.    单页Web应用(single page web application,SPA)
    
  2.    整个应用只有一个完整的页面
    
  3.    点击页面中的链接不会刷新页面, 本身也不会向服务器发请求
    
  4.    当点击路由链接时, 只会做页面的局部更新
    
  5.    **数据都需要通过ajax请求获取, 并在前端异步展现**
    

2.3 路由的理解

  1. 什么是路由?

​ a. 一个路由就是一个映射关系(key:value)

​ b. key为路由路径, value可能是function/component

  1. 路由分类

​ a. 后台路由: node服务器端路由, value是function, 用来处理客户端提交的请求并返回一个响应数据

​ b. 前台路由: 浏览器端路由, value是component, 当请求的是路由path时, 浏览器端前没有发送http请求, 但界面会更新显示对应的组件

  1. 后台路由

​ a. 注册路由: router.get(path, function(req, res))

​ b. 当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据

  1.    前端路由
    

​ a. 注册路由: <Route path="/about" component={About}>

​ b. 当浏览器的hash变为#about时, 当前路由组件就会变为About组件

3. react-router相关API

3.2 组件

  1. <BrowserRouter>

  2. <HashRouter>

  3. <Route>

  4. <Redirect>

  5. <Link>

  6. <NavLink>

  7. <Switch>

3.3 其它

  1. history对象

  2. match对象

  3. withRouter函数

4. 基本路由使用 举例说明

4.1 准备

  1. 下载react-router: npm install --save react-router-dom

  2. 引入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 如何编写路由组件

  1. 编写路由组件
  2. 在父路由中指定:
    1. 路由链接:如<NavLink>,<Link>,属性为to
    2. 路由:<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>
                &nbsp;&nbsp;
                <button onClick={() => this.showDetail(m.id)}>push查看</button>
                &nbsp;&nbsp;
                <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>
    )
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值