react構建後臺管理系統

先上一下效果圖:
登陸頁:css

clipboard.png
任意輸入帳號密碼(由於尚未後臺,不想作啥校驗了)
登陸後是這樣子的react

clipboard.png
很傳統有沒有,左邊是菜單導航,右邊是tabs區域。爲了讓系統顯得高大上,這裏還作了根據路由信息,判斷是否全屏顯示,來,看看咱們的全屏。git

clipboard.png

嗯,點擊右上角的家的圖案,就能夠返回主頁,退出圖案就是退出登陸啦啦啦。
囉嗦了這麼多效果圖,如今來說一下代碼吧。
項目的入口文件是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" />&nbsp;&nbsp;歡迎您&nbsp;{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

相關文章
相關標籤/搜索