美文网首页前端学习笔记
新人第020天---第一个项目

新人第020天---第一个项目

作者: cyuamber | 来源:发表于2017-08-07 17:53 被阅读43次

    终于,入职20天了。今天吃了烤串庆祝!

    最近一周使用react框架做了一个具有简单功能的异步监控平台,是接触react之后做的第一个项目,简单总结一下。

    一、开发需求

    一个异步监控平台,需要显示服务器的名称、进程名称以及进行一系列操作,包含:开始、停止、重启、显示日志等,没有设计图,给出的参考图如下:



    而这个项目又有些特殊的要求,需要控制的项目也更多,需要有:机器、组、进程这三个概念,因此,最终设计成了如下形式:



    如图,这是一台机器中的三个进程,分为两个进程组,每个组中对应着不同的进程,而这些进程都需要进行相应的操作。使用react开发,可以将这些内容分为组件,降低开发难度。

    二、开发环境

    本项目直接复用的组内其他项目的结构。主要基于通过对本部门业务项目的需要,在fis和webpack的基础上集成了一套打包方式(内部称eden)。部分依赖如下,供参考:

        "babel-core": "^6.5.2",
        "babel-loader": "^6.2.3",    
        "babel-preset-stage-0": "^6.5.0",
        "css-loader": "^0.26.1",
        "eden-remote-deploy": "^0.0.1", //eden版本
        "express": "^4.15.2",
                ... ...
        "q": "^1.5.0",
        "react-transform-hmr": "^1.0.4",
        "serve-static": "1.12.2",
        "style-loader": "^0.13.1",
        "url-loader": "^0.5.8",
        "webpack": "2.4.1",
        "webpack-dev-middleware": "1.10.2",
        "webpack-hot-middleware": "2.18.0",
        "webpack-merge": "^4.1.0"
    

    三、具体实现

    1. react页面结构搭建

    如开发需求中提到的,组件化开发可以降低开发的难度,但同时,在项目的开始如何分配组件就显得至关重要了。
    根据项目的需求,我一开始将这个app分成了四个组件,分别是:
    Header:图中的黑色条,项目的抬头,暂时用来显示标题,日后可以拓展到功能键的显示(扩展了一个登入-登出的功能);
    Server:图中的深灰色框框,用来显示每一台机器的容器;
    Title:图中的浅灰色条条中的三个按钮,用来控制一个进程组的动作;
    Structure:图中的表格部分,用来显示每一组进程的容器
    在确定了相关组件之后,我开始进行组件开发,之所以考虑将Title组件单独拿出来,是为了尽量简化Structure这个组件,因为,如果不这样做,Structure组件需要同时控制组进程和单个进程的操作,逻辑比较复杂;但是实际开发过程中,发现如果将Title组件独立出去,会导致更多的麻烦,主要出现在数据传输上,即,数据需要从Server传入Structure中,再传入title中,因此,最终删除了title组件。最终保留了三个组件:



    在确定好这些之后,就可以开始页面的搭建了。
    在每个组件中填入需要渲染的元素即可。本项目的主体是使用表格实现的。

    2. UI库使用

    第一次开发,使用了公司一直在用的antd库,主要使用的组件有:Button, Table, Icon, Tooltip, Tag, Modal, Row, Col等。
    在使用antd库的时候,有很多注意事项,这在我的另一篇文章中有提到,这里不做详述了。
    本项目的主体是使用antd中的Table组件搭起来的。该组件有两个主要的属性:columns&&dataSource。columns用来设置每一列的值,dataSource则用来选择数据源。最终使用<Table />进行生成。当然,该组件也有很多其他属性,本项目做的配置如下:


    其他组件在另一篇文章中也有所提及,因此不做详述;值得一提的是,在使用Modal组件时,发现其中的文字无法选择,后来发现是一个css3的属性:user-select设置成了none, 因此,在antd.min.css文件中进行了定制化主题,将所有的user-select属性值都改为了text(使用正则表达式 (?<=user-select:)none 进行向前匹配并进行替换,效率更高哦)。
    附:user-select的属性值:
    auto——默认值,用户可以选中元素中的内容
    text——用户可以选择元素中的文本
    element——文本可选,但仅限元素的边界内(只有IE和FF支持)
    all——在编辑器内,如果双击或上下文点击发生在子元素上,该值的最高级祖先元素将被选中。
    在所有的组件插入后,最重要的数据传输步骤来到了!前方高能。。。

    3. 交互实现

    该项目是一个异步管理项目,主要需要进行的数据交互是:点击按钮后发出不同的数据请求,从后端拉回新的返回数据,同时更新UI界面。
    要实现这样的异步传输系统,分为几个步骤:
    1)点击按钮的时候触发事件,同时传递参数;
    2)向指定接口传递数据;
    3)从指定接口获取最新数据,更新UI页面;
    这样,就完成了一个数据传输的过程。
    再看具体实现。
    首先是第一步,具体实现方法如下:

    <button onClick={ () => this.props.startAll({
        server_name:name})} 
        className='actionButton'
    >...</button>
    

    在一个button中绑定startAll方法,并传入server_name参数;
    接下来,是通过startAll方法向指定接口传参,这里使用的是react-refetch。使用react-refetch,首先需要引入,这里主要是引入connect:
    import { connect, PromiseState } from 'react-refetch'

    接着就是在项目中触发,本项目中选择的触发方式:

    export default connect (props=>({
    startAll: params=>({
        startAllResponse: {
        url:/smonitor/api/***,
        method:'POST',
        body: formurlencoded(params),
        force:true,
        headers: {
        'Content-Type':'application/x-www-form-urlencoded'
        }
        }
    })
    //通过这样的操作,将请求参数发出;
    

    最后,从指定接口获取数据并进行UI界面更新:
    要完成此操作,首先应该通过react的生命周期componentWillReceiveProps来完成,通过向此周期中传入nextProps参数,来检测当整个app的props改变之后,项目需要进行的操作。在此项目中,这一步需要显示从后端拉过来新的服务器状态,因此,需要仿照第二步的做法,新建一个refresh方法,并且重新向服务器请求参数:

    refreshList:params => ({
            refreshAllResponse: {
                url: `/smonitor/api/***`,
                method: 'POST',
                body: formurlencoded(params),
                force: true,
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            }
          }
        )
    

    之后,在componentWillReceiveProps生命周期中引入这个方法,来刷新整个页面的显示:

     componentWillReceiveProps(nextProps) {
            if (nextProps.startAllResponse && !nextProps.startAllResponse.pending && this.props.startAllResponse.pending) {
                const responseValue = nextProps.startAllResponse.value;
                if (responseValue.errno == 0) {
                    this.props.refreshList({
                        server_name:this.props.name
                    })
                }
            }
    

    通过这样的方式,就完成了页面的刷新显示。

    4. 状态管理引入

    这一步主要做的是引入redux管理机制。目前还没做,只提出设想。
    首先是将所有的动作(包含点击按钮后的行为)集成到action中,之后在reducer中写入生命周期中的内容,最后通过connect将recucer将module和action相连接。
    具体的实现了再补充过来。。。

    四、本地数据测试

    在整体的逻辑走通之后,接下来就是使用本地的mock数据进行调试。具体的格式要与服务器请求的相同。

    {
      "homepage": {
       "logout_url": "http:***,
        "user_info": {
            "uid": "344",
            "uname": "xuran",
            "email": "xuran@iwaimai.baidu.com"
        },
        "local-server": {
            "version": "3.3.1",
            "process_list": [
              {
                "group": "apilog01",
                "name": "apilog001",
                "description": "pid 2813, uptime 0:00:02",
                "statename": "STOPPED",
                "state": 0
              }
            ]
        },
        "error-server": {
            "version": "3.3.1",
            "process_list": [
              {
                "group": "apilog02",
                "name": "apilog001",
                "description": "pid 2813, uptime 0:00:02",
                "statename": "EXITED",
                "state": 100
              }
            ]
        }
      }
    }
    

    本地数据测试无误后,可以推代码到后端开发机上进行测试。

    五、坑。。。

    1. mock数据的配置问题:之前启动项目时,mock数据一直显示404,经查找之后发现,是mock数据路径没有被拦截成功的原因,这在eden的项目配置过程中需要重点注意;
    2. 注意上线环境与本机环境的区别。两个大坑:第一个是使用的iconfont字体的跨域问题,阿里cdn会拦截本厂域名,因此通过下载到本地并改变webpack配置来解决这一点;第二个是要将所有本地内容转换为线上内容,比如登出链接,就需要从模板中取。。。
    3. 处理数据时要考虑到数据结构可能进行扩充,因此需要进行多种考虑。本项目中,homepage下原先只有local-server这一个对象,后来又扩展了logout_urluser_info这两个字段,因此之前的数据读取方式不能再用,这是一开始开发时没有考虑到的情况。

    这样,算是跌跌撞撞完成了第一个项目的开发和上线。日后的优化方向:引入redux状态管理机制&&完善Eden。

    未完待续。。

    相关文章

      网友评论

        本文标题:新人第020天---第一个项目

        本文链接:https://www.haomeiwen.com/subject/isealxtx.html