好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

react如何实现侧边栏联动头部导航栏效果

项目中使用react+antd design+redux+react-reouter-dom

实现思路

编写路由表=》循环遍历路由表=》渲染侧边栏=》单击侧边栏获取相应的标签数据=》存入redux=》遍历循环redux数据渲染头部导航栏

路由表

const RouterTree = [
? ? {
? ? ? ? key: 'num_one',
? ? ? ? title: {
? ? ? ? ? ? icon: '',
? ? ? ? ? ? text: 'text'
? ? ? ? },
? ? ? ? children: [
? ? ? ? ? ? {
? ? ? ? ? ? ? ? key: '1',
? ? ? ? ? ? ? ? text: 'options1',
? ? ? ? ? ? ? ? path: '/option1',
? ? ? ? ? ? ? ? component: '',
? ? ? ? ? ? ? ? isOutSide: true,
? ? ? ? ? ? }
? ? ? ? ]

? ? },
? ? {
? ? ? ? key: 'num_two',
? ? ? ? title: {
? ? ? ? ? ? icon: '',
? ? ? ? ? ? text: 'text'
? ? ? ? },
? ? ? ? children: [
? ? ? ? ? ? {
? ? ? ? ? ? ? ? key: '2',
? ? ? ? ? ? ? ? text: 'text',
? ? ? ? ? ? ? ? path: '/option1',
? ? ? ? ? ? ? ? component: '',
? ? ? ? ? ? ? ? isOutSide: false
? ? ? ? ? ? }
? ? ? ? ]

? ? },
? ? {
? ? ? ? key: 'num_three',
? ? ? ? title: {
? ? ? ? ? ? icon: '',
? ? ? ? ? ? text: 'text'
? ? ? ? },
? ? ? ? children: [
? ? ? ? ? ? {
? ? ? ? ? ? ? ? key: '3',
? ? ? ? ? ? ? ? text: 'text',
? ? ? ? ? ? ? ? path: '/option1',
? ? ? ? ? ? ? ? component: '',
? ? ? ? ? ? ? ? isOutSide: false
? ? ? ? ? ? }
? ? ? ? ]

? ? },
]
export default RouterTree

侧边栏渲染

引入路由表,循环遍历渲染侧边栏

import React, { Component } from 'react'
import { Menu } from 'antd';
import { NavLink as Link, withRouter } from 'react-router-dom'
import RouterTree from '@/modules/route.js'

?render() {
? ? ? ? const { activityKey } = this.state || {}
? ? ? ? return (
? ? ? ? ? ? <div>
? ? ? ? ? ? ? ? <Menu
? ? ? ? ? ? ? ? ? ? onClick={this.handleClick}
? ? ? ? ? ? ? ? ? ? defaultSelectedKeys={['1']}
? ? ? ? ? ? ? ? ? ? defaultOpenKeys={['sub1']}
? ? ? ? ? ? ? ? ? ? selectedKeys={activityKey}
? ? ? ? ? ? ? ? ? ? mode="inline"
? ? ? ? ? ? ? ? ? ? inlineCollapsed={isToggle}
? ? ? ? ? ? ? ? >
? ? ? ? ? ? ? ? ? ? {RouterTree.map((item, index) => {
? ? ? ? ? ? ? ? ? ? ? ? return (
? ? ? ? ? ? ? ? ? ? ? ? ? ? <SubMenu
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? key={item.key}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? title={item.title.text}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? index={index}
? ? ? ? ? ? ? ? ? ? ? ? ? ? >
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {item.children && item.children.map((menuItem, menuIndex) => {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return (<Menu.Item
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? key={menuItem.key}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? index={menuIndex}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? >
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {menuItem.isOutSide ? <a href='http://HdhCmsTestbaidu测试数据' rel="noopener noreferrer">baidu</a> : <Link to={menuItem.path}>{menuItem.text}</Link>}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </Menu.Item>)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? })}
? ? ? ? ? ? ? ? ? ? ? ? ? ? </SubMenu>)
? ? ? ? ? ? ? ? ? ? })}
? ? ? ? ? ? ? ? </Menu>
? ? ? ? ? ? </div>
? ? ? ? )

由于单独使用redux不便,项目中引用react-redux,redux-thunk。

这里将侧边栏拆分为两个文件,一个是容器组件,一个为UI组件(以上的为UI组件)

容器组件(侧边栏)

容器组件为导出的组件,在容器组件中引入UI组件slide

import { connect } from 'react-redux'
import { business } from '@/tools/index.js'
import Slide from './slide'

const { processedArr } = business

const mapStoreToProps = (state) => {
? ? const { dynamicJump,activityKey} = state || {}
? ? let responseRoute = processedArr(dynamicJump)
? ? return {
? ? ? ? dynamicJump: [...responseRoute],
? ? ? ? activityKey:activityKey
? ? }
}

const mapDispatchToProps = (dispatch) => {
? ? return {
? ? ? ? updateRouter(item) {
? ? ? ? ? ? dispatch((dispatch) => {
? ? ? ? ? ? ? ? dispatch({
? ? ? ? ? ? ? ? ? ? type: 'UPDATED_ROUTING', item: { ...item }
? ? ? ? ? ? ? ? })
? ? ? ? ? ? })
? ? ? ? },
? ? ? ? activityKeys(key){
? ? ? ? ? ? dispatch((dispatch)=>{
? ? ? ? ? ? ? ? dispatch({
? ? ? ? ? ? ? ? ? ? type:'ACTIVITY_KEY',key:key
? ? ? ? ? ? ? ? })
? ? ? ? ? ? })
? ? ? ? }
? ? }
}

export default connect(mapStoreToProps, mapDispatchToProps)(Slide)

store

在src下新建一个store文件

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux'

let createHistory = require('history').createBrowserHistory
let history = createHistory()
let routerWare = routerMiddleware(history)

const dynamicJump = {
? ? dynamicJump: '这里设置默认值'(一般存放在session中),
? ? activityKey: '这里设置默认值',
}

const reducers = function (state = dynamicJump, action) {
? ? switch (action.type) {
? ? ? ? case 'UPDATED_ROUTING':
? ? ? ? ? ? state.dynamicJump =action.item
? ? ? ? ? ? break;
? ? ? ? case 'ACTIVITY_KEY':
? ? ? ? ? ? if (action.key !== undefined) {
? ? ? ? ? ? ? ? state.activityKey = action.key
? ? ? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? break;
? ? }
? ? return { ...state }
}

const store = createStore(reducers, applyMiddleware(thunk, routerWare))

// 订阅事件
store.subscribe(() => {
? ? let state = store.getState();
? ? sessionStorage.setItem('dynamicJump',JSON.stringify(state.dynamicJump))
? ? sessionStorage.setItem('activityKey',JSON.stringify(state.activityKey))
})

export default store

在根目录下将其注入进去(注意文件的引入位置)

import {Provider} from 'react-redux'
import store from './store/index.js'

ReactDOM.render(
? <Provider store={store}><App /></Provider>,
? document.getElementById('root')
);

头部导航栏

容器组件

import { connect } from 'react-redux'
import { push } from 'react-router-redux'
import { business } from '@/tools/index.js'
import Header from './head.jsx'

const { processedArr } = business

const mapStoreToProps = (state) => {
? ? const { dynamicJump, activityKey } = state
? ? let newRouteArr = processedArr(dynamicJump)
? ? return {
? ? ? ? dynamicJump: [...newRouteArr],
? ? ? ? activityKey: activityKey
? ? }
}

const mapDispatchToProps = (dispatch) => {
? ? return {
? ? ? ? removeKey(itemKey) {
? ? ? ? ? ? dispatch((dispatch, getStore) => {
? ? ? ? ? ? ? ? const { dynamicJump } = getStore() || {}
? ? ? ? ? ? ? ? let removeArr = processedArr(dynamicJump)
? ? ? ? ? ? ? ? const indexes = removeArr.findIndex((item) => item.key === itemKey)
? ? ? ? ? ? ? ? // 点击头部导航条的删除(即删除保存在redux的数组元素即可)
? ? ? ? ? ? ? ? if (removeArr.length > 1) {
? ? ? ? ? ? ? ? ? ? removeArr.splice(indexes, 1)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // 删除之后跳转到删除元素的前一个元素的路由地址
? ? ? ? ? ? ? ? let path = removeArr[indexes - 1] ? removeArr[indexes - 1].path : '/option1'
? ? ? ? ? ? ? ? let keys = removeArr[indexes - 1] ? removeArr[indexes - 1].key : 0
? ? ? ? ? ? ? ? if(keys===0){
? ? ? ? ? ? ? ? ? ? keys=removeArr[0].key
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? dispatch({
? ? ? ? ? ? ? ? ? ? type: 'UPDATED_ROUTING', item: { ...removeArr },
? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? dispatch({
? ? ? ? ? ? ? ? ? ? type: 'ACTIVITY_KEY', key: keys
? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? // 这里进行跳转
? ? ? ? ? ? ? ? dispatch(push(path))
? ? ? ? ? ? })
? ? ? ? },
? ? ? ? changeActiveKey(key) {
? ? ? ? ? ? dispatch((dispatch) => {
? ? ? ? ? ? ? ? dispatch({
? ? ? ? ? ? ? ? ? ? type: 'ACTIVITY_KEY', key: key
? ? ? ? ? ? ? ? })
? ? ? ? ? ? })
? ? ? ? }
? ? }
}


export default connect(mapStoreToProps, mapDispatchToProps)(Header)

这里存在着:如果删除头部组件的其中一个导航,那么需要跳转到该导航(删除的)的前一个路由地址,而这个操作在UI组件中是不方便的,这里我采取的方法是引入“history”模块(详细代码请移步到store.js),然后在容器组件中使用dispatch(push(path))跳转,也可以使用更为简单的方法,直接在容器组件中引入react-router的withRouter,包裹在最外层即:export default withRouter(connect(mapStoreToProps, mapDispatchToProps)(Header))

UI组件

render(){
? ?const { dynamicJump } = this.props || {}
? ?const { activeKey } = this.state || {}
?? ?<Tabs
?? ? ? ? ? ? hideAdd
?? ? ? ? ? ? onChange={this.onChange}
?? ? ? ? ? ? activeKey={activeKey}
?? ? ? ? ? ? type="line"
?? ? ? ? ? ? onEdit={this.onEdit}
?? ? ? ? ? ? className='tabs'
?? ? >
?? ? ? ? ? ? ? ? ?{ dynamicJump.map((item) => (
?? ? ? ? ? ? ? ? ? ? ? ? ? ?<TabPane tab={<Link to={item.path}>{item.text}</Link>} key={item.key} />
?? ? ? ? ? ? ? ? ? ?))}
?? ?</Tabs>
}

对于key值,可以使用react新增的钩子函数:getDerivedStateFromProps进行判断是否更行

static getDerivedStateFromProps(nextProps, preState) {
? ? ? ? const { activityKey, dynamicJump } = nextProps || {}
? ? ? ? const { activeKey } = preState || {}
? ? ? ? if (activityKey !== activeKey) {
? ? ? ? ? ? return {
? ? ? ? ? ? ? ? activeKey: activityKey
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return { allRoute: dynamicJump }
?}
?
?remove = targetKey => {
? ? ? ? this.removeKey(targetKey)
? ?}
? removeKey(key) {
? ? ? ? this.props.removeKey(key)
? ? }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文地址:https://blog.csdn.net/sky_blue6/article/details/107404128

查看更多关于react如何实现侧边栏联动头部导航栏效果的详细内容...

  阅读:56次