論React js的正確開啟方式 管理系統介面模組化實踐

晦若晨曦發表於2017-12-14

一、論管理系統的模組化

不管是給別人做專案,還是自己家的專案,一個網站、app總少不了一套管理系統。

管理系統是個很特殊的東西,功能很多,對介面要求不高,可複用性特別好,尤其適合做成模組化的框架來使用。

下面是一個典型的管理系統介面:

【圖一、管理系統介面】

temp1.jpg

在圖上已經圈出了管理系統的幾個大模組:

  • 使用者資訊、logo等所在的頂部資訊欄
  • 左側的導航欄
  • 主要展示區

根據React的思想,將整個網站視為一個app,現在三個大元件就很明確了。整個系統的流程就應當是點選導航欄之後,更換主要展示區所載入的元件實現不同的功能模組。

接下來就是進一步的細化主展示區的模組

【圖二、主展示區模組示意圖】

temp2.jpg

管理系統的資料展示也就是幾種主要方式,每次寫起來都要複製貼上一大堆的html程式碼導致很麻煩。進行模組化的處理之後,可以將主要精力放在對資料的處理上,而忽略介面的實現細節。大幅度提升之後的工作效率。

二、相關技術

與之前粗淺的React.js入門知識比起來,這次實踐中瞭解到了以下相關技術:

  • Javascript ES6
  • Webpack
  • React-router

隨著ES6標準的日益流行,現在前端的應用也愈發廣泛。相比起之前的javascript來說,ES6標準更趨近於java的寫法,對於我這種後端程式猿更為友好和親切。

Webpack一直是React優先選擇的前端模組化工具之一。可以將js、css甚至是圖片資源打包到同一個js檔案中。一來方便控制,二來通過減少網路請求次數以提高網站的載入速度。

React-router是React官方的也是目前唯一可用的路由庫。通過此庫即可實現“點選導航連更換主展示區元件”的路由功能。

三、編寫元件

1 總體框架

廢話不多說,直接上程式碼:

import React from 'react';
import ReactDOM from 'react/lib/ReactDOM';
import { Router, Route, hashHistory,Link } from 'react-router';
import Topnav from './topnav.js';
import Navbar from './navbar.js';
import {EditNormalUser,NormalUser,AdminUser,AddAdmin} from './userComponent.js';

class IndexWrapper extends React.Component {

    render () {
        return (
            <div className="wrapper preload">
                <header className="top-nav" id="top-nav">
                    <Topnav />
                </header>
                <aside className="sidebar-menu fixed" id="navbar">
                    <Navbar />
                </aside>

                <div className="main-container" id="main">
                    {this.props.children}
                </div>
            </div>
        )
    }
}

class Main extends React.Component{


    render(){
        var router = (
            <Router history={hashHistory} >
                <Route path="/" component={IndexWrapper}>
                    <Route path="/normal" component={NormalUser}/>
                    <Route path="/admin" component={AdminUser}/>
                    <Route path="/admin/add" component={AddAdmin}/>
                    <Route path="/normal/edit/:uid" component={EditNormalUser}/>
                </Route>
            </Router>
        );
        return router;
    }

};

複製程式碼

Router與Route就是兩個屬於React-router庫的元件。是實現路由功能的關鍵。 hashHistory是用來維護瀏覽器history的方式,另一種實現是browserHistory。 對應於/normal路徑,hashHistory的方式生成的URL如下:

http://localhost:8080/admin.html#/normal?_k=bptt31
複製程式碼

browserHistory則會跳轉到如下路徑:

http://localhost:8080/normal
複製程式碼

相比之下,hashHistory的方式對後端程式碼影響較小,故在此選擇了hashHistory。

Router維護了一個路由的上下文。根據約定呢,在Router下只能有一個元素,在此對應的就是根路徑的路由"/",對應的元件則是IndexWrapper,對整體框架的簡單包裝。

在React中,有個很重要的屬性:this.props.children,代表此元素中的子元素。在Main元件中可見對於根路徑的路由,對應的元件是IndexWrapper,其中除了頂部的Topnav和左側的Navbar元件之外,就使用了this.props.children屬性,根據路由載入不同的主展示區元件使用。

2、導航

本系統內的導航欄設計為最多二層的結構。包括兩種元件:

  • 單層的導航欄SingleNav
  • 雙層的導航欄MultiNav

在資料上,使用陣列來進行填充,樣例如下:

navtree : [
                {
                    name:"首頁",
                    component:"./home"
                },
                {
                    name:"使用者管理",
                    subnav:[
                        {
                            name:"普通使用者管理",
                            component:"/normal"
                        },{
                            name:"管理員管理",
                            component:"/admin"
                        },
                    ]
                }
            ]
複製程式碼

而對應於陣列的處理迴圈如下:

var navs = [];
        for(var i=0;i<this.state.navtree.length;i++){
            var nav = this.state.navtree[i];
            if(!nav)
            continue;
            if(nav.subnav){
                navs.push(<MultiNav key={"nav-multibar-"+i} nav={nav} ></MultiNav>);
            }else{
                navs.push(<SingleNav key={"nav-singlebar-"+i} nav={nav} ></SingleNav>);
            }
        }
複製程式碼

實際上呢,component指向的是路由的路徑,名稱什麼的是一個歷史遺留問題^_^

在導航這裡呢,又涉及到一個路由上很重要的元件:Link元件

<Link to={this.props.nav.component} activeClassName="active">
複製程式碼

Link元件會被編譯為一個a標籤,to則被編譯為href屬性,指向指定的url。同時解決了一個選中狀態的問題,當被選中時會自動新增類active,這也是前端常用的選中狀態類。

要注意的是,Link必須屬於某一個路由上下文中。也就是在Router元件之內。在最初的時候並沒有使用Router對整個頁面進行包裹,導致報錯提示Link不再RouterContext之中,編譯出href也為空。

3、介面UI元件案例

將UI元件化是節約日後工作量的重頭戲,下面就以一個簡單的例子來說明,此處並沒有什麼新的技術加入,所以直接上程式碼:

export class SmartBox extends React.Component{
    render (){
        var options = [];
        if(this.props.option){
            if(this.props.option.reload){
                options.push(
                    <a href="#" className="widget-refresh-option" onClick={this.props.option.reload}>
                        <i className="fa fa-refresh"></i>
                    </a>
                )
            }
            if(this.props.option.add){
                if(typeof add == "function"){
                    options.push(
                        <a href="#" className="widget-refresh-option" onClick={this.props.option.add}>
                            <i className="fa fa-plus"></i>
                        </a>
                    )
                }else{
                    options.push(
                        <Link to={this.props.option.add}>
                            <i className="fa fa-plus"></i>
                        </Link>
                    )
                }
            }
        }
        return (
            <div className="padding-md">
                {this.props.index}
                <div className="smart-widget">
                    <div className="smart-widget-header">
                        {this.props.title}
                        <span className="smart-widget-option">
								<span className="refresh-icon-animated">
									<i className="fa fa-circle-o-notch fa-spin"></i>
								</span>
                            {options}
                        </span>
                    </div>
                    <div className="smart-widget-inner">
                        <div className="smart-widget-body">
                            {this.props.children}
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}
複製程式碼

這就是標準的管理系統主模組框架。包括了頂部的麵包屑導航和內容的外框包圍。兩個可選按鈕:重新整理,新增

此處同樣使用了this.props.children屬性來新增子節點。

元件的實際使用如下:

render (){
        var index = (
            <ul className="breadcrumb">
                <li>使用者管理</li>
                <li>管理員</li>
                <li>列表</li>
            </ul>
        );
        return (
            <SmartBox title="使用者資訊列表" index={index}
                      option={{reload:this.loadPage.bind(this),add:"/admin/add"}}>
                <DataTable index={this.state.index} data={this.state.data} buttons={this.state.buttons}/>
                <Pager pagecount={this.state.pagecount} last={this.state.last} callback={this.loadPage.bind(this)} />
            </SmartBox>
        )
    }
複製程式碼

在此案例中使用了SmartBox,DataTable和Pager三個UI元件,實現了一個標準的資料列表。

四、專案打包

最後的工作則是使用webpack對此專案進行預編譯和打包,在這裡需要安裝nodejs以使用npm工具。

首先要安裝webpack:

npm install webpack -g
複製程式碼

然後是對webpack進行配置,配置檔案如下:

var webpack = require('webpack')

module.exports = {
    entry: './application.js',
    output: {
        filename: '../main.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                loader: "babel",
                query: {
                    presets: ['react', 'es2015']
                }
            }
        ]
    }
}

複製程式碼

這個配置檔案嘛,他就做了三件微小的工作:

  • 指定入口
  • 指定輸出檔案
  • 指定js檔案的載入器。

最後呢,我先執行了npm install,然後跑了webpack,就打包成了一個main.js檔案。

在html中只需要引入main.js檔案即可,無需再引入React.js相關的檔案。

當然如果願意,可以將網頁中所有的資源都用這種方式引入。

五、結束

一個簡單的web頁面模組化工作基本就此完成。

隨著現在web技術的飛快發展,前端的工程化、模組化已經是大勢所趨。不再像以前一樣隨便寫寫html和css,js,用幾行jquery就能完成工作了。

現在流行的元件化框架,包括react.js,angular.js,vue.js等,都是這種趨勢的產物。雖然作為一個主攻後端的工程師,對於前端技術必要的瞭解和掌握也是必不可少的。

相關文章