SPA与路由

  1. 单页Web 应用(single page web application,SPA)

  2. 整个应用只有一个完整的页面

  3. 点击页面中的链接不会刷新页面, 本身也不会向服务器发请求

  4. 当点击路由链接时, 只会做页面的局部更新

  5. 数据都需要通过ajax 请求获取, 并在前端异步展现

  6. 路由

    一个路由就是一个映射关系(key:value),key 为路由路径, value 可能是function/component。

    • 前端路由
    • 后端路由

react-router基本使用

相关文档:http://react-guide.github.io/react-router-cn/index.html

英文原版:https://reactrouter.com/web/guides/quick-start

  1. 安装

    1
    yarn add react-router-dom
  2. 使用BrowserRouter组件包裹所有组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { BrowserRouter } from 'react-router-dom'
    import App from './components/app'

    ReactDOM.render(
    <BrowserRouter><App /></BrowserRouter>
    ,
    document.getElementById('root')
    );
  3. 在根组件中引入相关需要的路由组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    import React, { Component } from 'react'
    import { NavLink, Switch, Route, Redirect } from 'react-router-dom'
    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'>
    <NavLink className='list-group-item' to='/about'>
    about
    </NavLink>
    <NavLink className='list-group-item' to='/home'>
    home
    </NavLink>
    </div>
    </div>
    <div className='col-xs-6'>
    <div className='panel'>
    <div className='panel-body'>
    <Switch>
    <Route path='/about' component={About}></Route>
    <Route path='/home' component={Home}></Route>
    <Redirect to='/about' />
    </Switch>
    </div>
    </div>
    </div>
    </div>
    </div>
    )
    }
    }

思想:重新包装一下NavLink组件,为其添加自己的属性。

1
2
3
4
5
6
7
8
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'

export default class MyNavLink extends Component {
render() {
return <NavLink {...this.props} activeClassName='activeClass' />
}
}

使用时导入自己的组件MyNavLink即可。

嵌套路由

a8f9bc88-63c5-415e-8564-3a999e113aa9

在home组件中嵌套两个路由,home组件需要判断显示哪个路由,因此使用Switch组件进行包裹。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React, { Component } from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import MyNavLink from '../components/myNavLink'
import News from './news'
import Message from './message'
export default class Home extends Component {
render() {
return (
<div>
<h2>Home Route compoent</h2>
<div>
<ul className='nav nav-tabs'>
<li>
<MyNavLink to='/home/news'>News</MyNavLink>
</li>
<li>
<MyNavLink to='/home/message'>Message</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>
)
}
}

在News或者Message组件中正常定义组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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' },
{ id: 4, title: 'message004' }
]
this.setState({ messages })
}, 1000)
}
render() {
return (
<ul>
<li>
{this.state.messages.map((m, index) => (
<li key={index}>
<a href='???'>{m.title}</a>
</li>
))}
</li>
</ul>
)
}
}

路由组件传参

通过链接传递数据

1
2
3
4
<Route
path='/home/message/messagedetail/:id'
component={messageDetail}
/>

:id表示在这个位置为收集一个键为id的对象。

接受参数,在跳转的组件中通过props.parmas接受参数。

1
const { id } = this.props.match.params

两种路由跳转方式

两种方式分别为replacepush。前者不会记录在历史记录里而后者会被记录。

aaa0112c-7bf7-49f1-ba11-132303ba5901

1
2
3
4
// 将ID作为参数传入函数
<button onClick={() => this.showDetail2(m.id)}>
replace()查看
</button>

AntDesign库

官方:https://ant.design/index-cn

  1. 安装(手机端)

    1
    yarn add antd-mobile
  2. 简单使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import React, { Component } from 'react'
    import { Button, Toast } from 'antd-mobile'
    import 'antd-mobile/dist/antd-mobile.css'
    export default class App extends Component {
    handClick() {
    Toast.info('666')
    }
    render() {
    return (
    <Button type='primary' onClick={this.handClick}>
    按钮
    </Button>
    )
    }
    }

按需引入

参考:按需加载

  1. 安装插件

    1
    yarn add react-app-rewired babel-plugin-import customize-cra -D
  2. 修改package.json脚本运行文件

    1
    2
    3
    4
    5
    "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom"
    }
  3. 创建config-overrides.js文件

    1
    2
    3
    4
    const { fixBabelImports, override } = require('customize-cra')
    module.exports = override(
    fixBabelImports('import', { libraryName: 'antd-mobile', style: 'css' })
    );