论React js的正确打开方式 管理系统界面模块化实践

一、论管理系统的模块化

不管是给别人做项目,还是自己家的项目,一个网站、app总少不了一套管理系统。

管理系统是个很特殊的东西,功能很多,对界面要求不高,可复用性特别好,尤其适合做成模块化的框架来使用。

下面是一个典型的管理系统界面:

【图一、管理系统界面】

在图上已经圈出了管理系统的几个大模块:

  • 用户信息、logo等所在的顶部信息栏
  • 左侧的导航栏
  • 主要展示区

根据React的思想,将整个网站视为一个app,现在三个大组件就很明确了。整个系统的流程就应当是点击导航栏之后,更换主要展示区所加载的组件实现不同的功能模块。

接下来就是进一步的细化主展示区的模块

【图二、主展示区模块示意图】

管理系统的数据展示也就是几种主要方式,每次写起来都要复制粘贴一大堆的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等,都是这种趋势的产物。虽然作为一个主攻后端的工程师,对于前端技术必要的了解和掌握也是必不可少的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值