react中实现导航栏状态与地址绑定

一、项目初始化

1. 安装与运行

构建项目:yarn create react-app my-app
启动:yarn start
当然也可以使用npm:

  • 全局安装:npm install -g create-react-app
  • 构建项目:npx create-react-app my-app
  • 启动:npm start

2.安装路由依赖

在项目中执行:npm install react-router-dom --save

3.在App.js中引入router

由于简单演示,就不单独对router进行封装了。
安装完成后,我们在App.js中引入路由相关组件BrowserRouterRouteSwitchRedirect
在顶部引入:import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
详细代码如下:

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
import React, { Component } from 'react';
import Home from '@/views/home'
import Study from '@/views/study'
import Type from '@/views/type'
import Label from '@/views/label'
import About from '@/views/about'
import { Layout } from 'antd'
import Header from '@/components/Header'
import Persional from '@/components/Persional'
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
const { Footer, Content, Sider} = Layout;
// 导入子组件
class App extends Component {
render() {
return (
<div className="App" >
<Layout>
<Sider>
<Persional />
</Sider>
<Content>
<Router>
<Header />
<Switch>
<Route path="/home" exact component={Home}></Route>
<Route path="/study" component={Study}></Route>
<Route path="/type" component={Type}></Route>
<Route path="/label" component={Label}></Route>
<Route path="/about" component={About}></Route>
<Redirect from="/*" to="/home"></Redirect>
</Switch>
<Footer>Footer</Footer>
</Router>
</Content>
</Layout>
</div>
);
}
}

export default App;

这里用到了antd的Layout布局组件进行布局
首先我们将我们的视图组件引入进来(import Home from '@/views/home'),并在Route标签中配置:(以home为例)<Route path="/home" exact component={Home}></Route>

4.编写Header头部导航组件

在components目录下新建Header目录,并在其目录下新建index.js及index.scss文件,这里使用scss进行编写。
安装命令:

1
2
npm install node-sass --save-dev 
npm install sass-loader --save-dev

为了实现导航栏状态与地址联动,关键是要实现组件初始化时的处理逻辑,也就是组件挂载的时候,即在生命周期函数componentDidMount中实现。
要实现以下两点:

  • 修改当前地址对应导航栏状态
  • 监听浏览器前进后退,即监听history对象
    关键代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    componentDidMount = () => {
    let moren = this.props.location.pathname
    let text = moren.substring(moren.lastIndexOf('/') + 1, moren.length)
    // 当访问的目录不在这个数组里时候,当前状态是home,即重定向到home页面
    !['home', 'study', 'type', 'label', 'about', 'search'].includes(text) && (text = 'home')
    this.setState({
    current: text
    })
    // 监听history变化
    history.listen((event) => {
    let test = event.pathname
    let text = test.substring(test.lastIndexOf('/') + 1, test.length)
    this.setState({
    current: text
    })
    })
    }
    组件完整代码如下:
    index.js:
    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    import React, { Component }  from 'react';
    import { Row, Col, Menu } from 'antd';
    import { Link, withRouter } from 'react-router-dom'
    import { HomeOutlined, FolderOpenOutlined, AppstoreOutlined, PushpinOutlined, UserOutlined, SearchOutlined } from '@ant-design/icons';
    import './index.scss'
    import { createBrowserHistory } from 'history';
    const history = createBrowserHistory() // history模式

    class Header extends Component {
    constructor(props) {
    super(props);
    this.state = {
    logo: '',
    current: 'home'
    }
    }
    handleClick = e => {
    this.setState({ current: e.key });
    }
    componentDidMount = () => {
    let moren = this.props.location.pathname
    let text = moren.substring(moren.lastIndexOf('/') + 1, moren.length)
    !['home', 'study', 'type', 'label', 'about', 'search'].includes(text) && (text = 'home')
    this.setState({
    current: text
    })
    history.listen((event) => {
    let test = event.pathname
    let text = test.substring(test.lastIndexOf('/') + 1, test.length)
    this.setState({
    current: text
    })
    })
    }
    render() {
    const { current } = this.state;
    return(
    <div className="header-wrapper">
    <Row>
    <Col span={18} push={6} className="right-box">
    <Menu onClick={this.handleClick} selectedKeys={[current]} mode="horizontal">
    <Menu.Item key="home" icon={<HomeOutlined />}>
    <Link to="/home">首页</Link>
    </Menu.Item>
    <Menu.Item key="study" icon={<FolderOpenOutlined />}>
    <Link to="/study">学习</Link>
    </Menu.Item>
    <Menu.Item key="type" icon={<AppstoreOutlined />}>
    <Link to="/type">分类</Link>
    </Menu.Item>
    <Menu.Item key="label" icon={<PushpinOutlined />}>
    <Link to="/label">标签</Link>
    </Menu.Item>
    <Menu.Item key="about" icon={<UserOutlined />}>
    <Link to="/about">关于</Link>
    </Menu.Item>
    <Menu.Item key="search" icon={<SearchOutlined />}>
    搜索
    </Menu.Item>
    </Menu>
    </Col>
    <Col span={6} pull={18} className="left-box">
    <strong className="logo-name">Deng</strong>
    </Col>
    </Row>
    </div>
    )
    }
    }
    export default withRouter(Header)
    注意:为了能够拿到this.props.location.pathname,需要使用withRouter处理组件,并把Header组件放在BrowserRouter标签中。
    这样就能够实现导航栏状态与地址绑定了

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!