先上一下效果圖:
登陸頁:css
任意輸入帳號密碼(由於尚未後臺,不想作啥校驗了)
登陸後是這樣子的react
很傳統有沒有,左邊是菜單導航,右邊是tabs區域。爲了讓系統顯得高大上,這裏還作了根據路由信息,判斷是否全屏顯示,來,看看咱們的全屏。git
嗯,點擊右上角的家的圖案,就能夠返回主頁,退出圖案就是退出登陸啦啦啦。
囉嗦了這麼多效果圖,如今來說一下代碼吧。
項目的入口文件是app.js,可能後續會用redux,因此先引進來再說。github
import React, { Component } from 'react'; import { Provider } from 'react-redux' import './App.css'; import store from './store' import {Router} from './routes/router' class App extends Component { render() { return ( <Provider store={store}> <Router/> </Provider> ); } } export default App;
接着就是路由的配置啦。這裏主要用到了react router4進行路由的切換。redux
export const Router = () => ( <BrowserRouter> <div> <Switch> <Route path="/login" component={Login} /> <Redirect from="/" exact to="/login"/>{/*注意redirect轉向的地址要先定義好路由*/} <AuthorizedRoute path="/layout" component={Layout} /> <Route component={NoFound}/> </Switch> </div> </BrowserRouter> )
經過這個路由配置,登陸後就會進入layout.js.這個類呢,AuthorizedRoute.js,就是作路由權限控制的。若是說頁面須要登陸後才能查看,就用這個組件設置路由信息。裏面的內容也很少,就是看一下sessionStorage裏面有沒有存儲用戶登陸信息,沒有就重定向會登陸頁唄。session
import React from 'react' import { Route, Redirect } from 'react-router-dom' class AuthorizedRoute extends React.Component { render() { const { component: Component, ...rest } = this.props const isLogged = sessionStorage.getItem("userName") != null ? true : false; return ( <Route {...rest} render={props => { return isLogged ? <Component {...props} /> : <Redirect to="/login" /> }} /> ) } } export default AuthorizedRoute
好了,那麼如今就到了編寫layout的內容了。左邊是菜單導航欄,右邊是tabs,這裏都是用antd的組件。爲了簡化代碼,我選擇了在router.js裏面寫好菜單對象類,這裏經過遞歸生成菜單組件。antd
class CreateMenuList extends React.Component { createMenu(data) { const childMenuData = data.child; let childMenu = <div></div>; if (childMenuData && childMenuData.length) { childMenu = childMenuData.map((item) => { return this.createMenu(item); }); return <SubMenu key={data.id} title={data.name}>{childMenu}</SubMenu> } else { return <Menu.Item key={data.id}><NavLink component={data.component} isfull={data.isFullScreen + ''}to={data.path} onClick={this.props.addTabs}>{data.name}</NavLink></Menu.Item> } } render() { return ( <Menu mode="vertical" theme="dark"> { menus.map((item) => { return this.createMenu(item); }) } </Menu> ); } }
Menu.Item裏面那麼多屬性值,都是爲了點擊的時候去調用tabs的add函數。而後動態生成tabs。isfull是判斷是否全屏顯示,若是全屏顯示就給layout組件最外層添加一個class,在這個class裏面寫一下樣式,隱藏掉菜單導航欄,tabs區域等,是否是有點機智呢。
菜單導航和antd的tabs聯繫在一塊兒,其實就是經過在tasb裏面放route,這裏能夠先在外面判斷一下是否是notFound。我又是在route.js裏面弄了個變量,以key-value的形式保存指向的組件對象。react-router
export const menuObject = { 'home': Home, 'operation': Operation } const panes = [ { title: '主頁', url: '/layout/home', key: 'newTab0', component: 'home', isFullScreen: false }, ]; //遞歸panes對象,生成tabs <div className="page-content"> <Tabs hideAdd onChange={this.onChange} activeKey={this.state.activeKey} type="editable-card" onEdit={this.onEdit} > {this.state.panes.map( pane => { let route = null; if(menuObject.hasOwnProperty(pane.component)) { route = <Route path={pane.url} exact component={menuObject[pane.component]} />; } else { route = <Route component={NoFound}/>; } return <TabPane tab={pane.title} key={pane.key}> {route} </TabPane> } )} </Tabs> </div>
點擊左邊導航的時候,調用父視圖傳過來的addTabs方法。在tabs的刪除、修改方法裏面,經過props.hsitory去修改路由。整個layout的代碼貼出來吧。app
class Layout extends React.Component { constructor(props) { super(props); this.newTabIndex = 1; this.state = { collapsed: false, activeKey: panes[0].key, isFullScreen: false, panes }; } logout = () => { this.props.history.push('/login') } goHome = () => { this.setState({isFullScreen: false}); this.props.history.push('/layout/home') let matchArray = this.state.panes.filter((item) => item.url === '/layout/home'); if(matchArray.length === 0) { let activeKey = `newTab${this.newTabIndex++}`; let panes = this.state.panes; panes.push({title: '主頁', url: '/layout/home', component: 'home' , key: activeKey }); this.setState({ panes, activeKey }); } else { this.setState({activeKey: matchArray[0].key}); } } add = (event) => { let url = event.currentTarget.getAttribute('href'); let isFullScreen = event.currentTarget.getAttribute('isfull'); if(isFullScreen === 'true') { this.setState({ isFullScreen: true }) } let matchArray = this.state.panes.filter((item) => item.url === url); if(matchArray.length === 0) { let activeKey = `newTab${this.newTabIndex++}`; let panes = this.state.panes; panes.push({ isFullScreen: isFullScreen, title: event.currentTarget.innerHTML, component: event.currentTarget.getAttribute('component'), url: url, key: activeKey }); this.setState({ panes, activeKey }); } else { this.setState({activeKey: matchArray[0].key}); } } onChange = (activeKey) => { let matchArray = this.state.panes.filter((item) => item.key === activeKey); this.setState({ isFullScreen: matchArray[0].isFullScreen }) this.props.history.push(matchArray[0].url); this.setState({ activeKey }); } onEdit = (targetKey, action) => { this[action](targetKey); } remove = (targetKey) => { let activeKey = this.state.activeKey; if (activeKey === targetKey) { let nextActiveIndex; this.state.panes.forEach((pane, i) => { if (pane.key === targetKey) { nextActiveIndex = i - 1; } }); if(nextActiveIndex > 0) { activeKey = this.state.panes[nextActiveIndex].key; this.props.history.push(this.state.panes[nextActiveIndex].url); } } const panes = this.state.panes.filter(pane => pane.key !== targetKey); this.setState({ panes, activeKey }); } render() { var fulllScreenClass = this.state.isFullScreen ? 'fullScreen' : ''; return <div className={"layout " + fulllScreenClass}> <div className="header"> <span>指標監控管理系統</span> <span> <span><Avatar icon="user" /> 歡迎您 {sessionStorage.getItem('userName')}</span> <Icon type="home" onClick={this.goHome.bind(this)}/> <Icon type="logout" onClick={this.logout.bind(this)}/> </span> </div> <div className={"content "}> <nav className="context-nav"> <CreateMenuList addTabs={this.add}/> </nav> <div className="page-content"> <Tabs hideAdd onChange={this.onChange} activeKey={this.state.activeKey} type="editable-card" onEdit={this.onEdit} > {this.state.panes.map( pane => { let route = null; if(menuObject.hasOwnProperty(pane.component)) { route = <Route path={pane.url} exact component={menuObject[pane.component]} />; } else { route = <Route component={NoFound}/>; } return <TabPane tab={pane.title} key={pane.key}> {route} </TabPane> } )} </Tabs> </div> </div> </div> } componentDidMount() { this.props.history.push('/layout/home') } }
總結一下,設置路由信息,先進入登陸頁,登陸頁後進去layout.js,在layout.js裏面加載菜單,修改tabs的代碼讓它和路由相關,並把路由信息放在tabs下面從而實現點擊左邊菜單,tabs下面能顯示路由渲染的組件。代碼路徑:https://github.com/supportlss...dom