任意输入账号密码(因为还没有后台,不想做啥校验了)
登录后是这样子的
很传统有没有,左边是菜单导航,右边是tabs区域。为了让系统显得高大上,这里还做了根据路由信息,判断是否全屏显示,来,看看我们的全屏。
嗯,点击右上角的家的图案,就可以返回主页,退出图案就是退出登录啦啦啦。
啰嗦了这么多效果图,现在来讲一下代码吧。
项目的入口文件是app.js,可能后续会用redux,所以先引进来再说。
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进行路由的切换。
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里面有没有存储用户登录信息,没有就重定向会登录页呗。
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里面写好菜单对象类,这里通过递归生成菜单组件。
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的形式保存指向的组件对象。
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的代码贴出来吧。
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: '主页',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,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...