先上一下效果图:
登录页:
任意输入账号密码(因为还没有后台,不想做啥校验了)
登录后是这样子的
很传统有没有,左边是菜单导航,右边是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: '主页', 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...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。