react如何實(shí)現(xiàn)側(cè)邊欄聯(lián)動(dòng)頭部導(dǎo)航欄效果
項(xiàng)目中使用react+antd design+redux+react-reouter-dom
實(shí)現(xiàn)思路
編寫(xiě)路由表=》循環(huán)遍歷路由表=》渲染側(cè)邊欄=》單擊側(cè)邊欄獲取相應(yīng)的標(biāo)簽數(shù)據(jù)=》存入redux=》遍歷循環(huán)redux數(shù)據(jù)渲染頭部導(dǎo)航欄
路由表
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
側(cè)邊欄渲染
引入路由表,循環(huán)遍歷渲染側(cè)邊欄
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 rel="noopener noreferrer">baidu</a> : <Link to={menuItem.path}>{menuItem.text}</Link>} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? </Menu.Item>) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? })} ? ? ? ? ? ? ? ? ? ? ? ? ? ? </SubMenu>) ? ? ? ? ? ? ? ? ? ? })} ? ? ? ? ? ? ? ? </Menu> ? ? ? ? ? ? </div> ? ? ? ? )
由于單獨(dú)使用redux不便,項(xiàng)目中引用react-redux,redux-thunk。
這里將側(cè)邊欄拆分為兩個(gè)文件,一個(gè)是容器組件,一個(gè)為UI組件(以上的為UI組件)
容器組件(側(cè)邊欄)
容器組件為導(dǎo)出的組件,在容器組件中引入U(xiǎn)I組件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下新建一個(gè)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: '這里設(shè)置默認(rèn)值'(一般存放在session中), ? ? activityKey: '這里設(shè)置默認(rèn)值', } 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
在根目錄下將其注入進(jìn)去(注意文件的引入位置)
import {Provider} from 'react-redux' import store from './store/index.js' ReactDOM.render( ? <Provider store={store}><App /></Provider>, ? document.getElementById('root') );
頭部導(dǎo)航欄
容器組件
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) ? ? ? ? ? ? ? ? // 點(diǎn)擊頭部導(dǎo)航條的刪除(即刪除保存在redux的數(shù)組元素即可) ? ? ? ? ? ? ? ? if (removeArr.length > 1) { ? ? ? ? ? ? ? ? ? ? removeArr.splice(indexes, 1) ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? // 刪除之后跳轉(zhuǎn)到刪除元素的前一個(gè)元素的路由地址 ? ? ? ? ? ? ? ? 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 ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? ? ? // 這里進(jìn)行跳轉(zhuǎn) ? ? ? ? ? ? ? ? dispatch(push(path)) ? ? ? ? ? ? }) ? ? ? ? }, ? ? ? ? changeActiveKey(key) { ? ? ? ? ? ? dispatch((dispatch) => { ? ? ? ? ? ? ? ? dispatch({ ? ? ? ? ? ? ? ? ? ? type: 'ACTIVITY_KEY', key: key ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? }) ? ? ? ? } ? ? } } export default connect(mapStoreToProps, mapDispatchToProps)(Header)
這里存在著:如果刪除頭部組件的其中一個(gè)導(dǎo)航,那么需要跳轉(zhuǎn)到該導(dǎo)航(刪除的)的前一個(gè)路由地址,而這個(gè)操作在UI組件中是不方便的,這里我采取的方法是引入“history”模塊(詳細(xì)代碼請(qǐng)移步到store.js),然后在容器組件中使用dispatch(push(path))跳轉(zhuǎn),也可以使用更為簡(jiǎn)單的方法,直接在容器組件中引入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> }
對(duì)于key值,可以使用react新增的鉤子函數(shù):getDerivedStateFromProps進(jìn)行判斷是否更行
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) ? ? }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
React教程之封裝一個(gè)Portal可復(fù)用組件的方法
react的核心之一是組件,下面這篇文章主要給大家介紹了關(guān)于React教程之封裝一個(gè)Portal可復(fù)用組件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01React如何利用相對(duì)于根目錄進(jìn)行引用組件詳解
這篇文章主要給大家介紹了關(guān)于React如何使用相對(duì)于根目錄進(jìn)行引用組件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10詳解React項(xiàng)目中eslint使用百度風(fēng)格
這篇文章主要介紹了React項(xiàng)目中eslint使用百度風(fēng)格,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09React應(yīng)用框架Dva數(shù)據(jù)流向原理總結(jié)分析
這篇文章主要為大家介紹了React 應(yīng)用框架Dva數(shù)據(jù)流向原理總結(jié)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12