美文网首页全栈工程师修炼精彩好文正能量使者
动手实践用Gulp+Webpack构建纯前端React应用

动手实践用Gulp+Webpack构建纯前端React应用

作者: liuwill | 来源:发表于2016-08-20 15:30 被阅读4274次

    最近构思了一个练手项目,应用react实现程序的逻辑,从而进一步学习React框架开发。这次的例子是一个纯前端的简单应用,模拟实现图片上传和展示功能。应用中,使用sessionStorage存储图片数据,并且将sessionStorage中存储的图片数据,以列表的形式展示出来。

    目录结构

    用Webpack打包React应用

    Webpack 是一个前端资源加载/打包工具,只需要相对简单的配置就可以提供前端工程化需要的各种功能。之前的例子中,对react的模块化,采用的是requirejs的AMD方式,使用Webpack之后,我们就可以使用nodejs的commonjs方式编写模块化的js代码。通过webpack,会将所有依赖的资源打包成一个单独的bundle,包含应用的逻辑代码,还有依赖的模块。

    如果使用jsx格式编写混编的js和html代码,还需要安装相应的loader,才能成功打包,使用的是babel-loader。这里的loader除了jsx之外,根据需要,还可以支持sass等其他格式。

    安装相应的npm依赖包

    npm install react --save-dev
    npm install react-dom --save-dev
    npm install webpack --save-dev
    npm install babel-loader --save-dev
    

    跟所有的应用程序一样,react也需要有一个入口点,webpack会从入口点开始,对所有的依赖文件进行打包,在webpack.config.js配置文件中,进行相应的配置;entry就是入口点

    module.exports = {
        entry:[
            './app/main.js'
        ],
        output: {
            path: __dirname + '/assets/',
            publicPath: "/assets/",
            filename: '[name].bundle.js'
        },
        resolve:{},
        module: {
            loaders: [
                /*{
                    test: /\.scss$/,
                    loaders: ["style", "css", "sass"]
                },*/{
                    test: /\.js$/,
                    loaders: ['babel-loader'],
                    include: __dirname + '/app/'
                },
                { test: /\.jsx?$/, loaders: ['babel','jsx?harmony']}
            ]
        },
        plugins:[]
    };
    

    使用Gulp构建项目

    为了开发和调试方便,引入构建工具gulp,主要使用到的插件包括:gulp-connectgulp-sassgulp-webpackgulp-uglify。分别使用npm安装对应的模块,npm install gulp --save-dev

    项目开发中,简单的实现了几个Task,进行项目打包和构建。

    var connect = require('gulp-connect');
    var gulpWebpack = require('gulp-webpack');
    var bower = require('gulp-bower');
    var uglify = require('gulp-uglify');
    var sass = require('gulp-sass');
    var webpackConfig = require('./webpack.config');
    
    gulp.task('bower', function() {
        return bower('./bower_components')
            .pipe(gulp.dest('./static/lib/'));
    });
    
    gulp.task('easy_webpack',function(){
        gulp.src('./app/main.js')
            .pipe(gulpWebpack(webpackConfig))
            .pipe(uglify())
            .pipe(gulp.dest('./assets/scripts/'))
    });
    
    gulp.task('easy_sass', function () {
        return gulp.src(path.SASS + '/**/*.scss')
            .pipe(sass().on('error', sass.logError))
            .pipe(gulp.dest('./assets/styles/'));
    });
    
    gulp.task('easy_build',['bower','easy_webpack','easy_sass'], function () {});
    
    gulp.task('staticserver', function() {
        connect.server({
            port:3333,
        });
    });
    

    React的组件

    搭建好环境之后,react的使用非常方便,把html根据需要拆分成不同的模块就可以直接在jsx语法的代码中混合编写,ReactDom.render就可以把模版转换成html代码,并且把html模块代码嵌入到指定的dom对象中,<代表往后是html代码,当作html解析,{代笔往后是js代码,当作js解析,需要注意的是,因为class是关键字,所以需要把class替换成className,把for替换成htmlFor。

    var React = require('react');
    var ReactDOM = require('react-dom');
    
    module.exports = React.createClass({
        handleClick:function(event){
            console.log(event.target);
        },
        render: function() {
            return (
                <div className="img-item">
                    <div className="img-view" onClick="{this.handleClick}">
                        <img className="picture" src={this.props.imgData.file}/>
                    </div>
                    <div className="img-info">
                        <span className="img-name">{this.props.imgData.name}</span>
                        <span className="img-type">{this.props.imgData.format}</span>
                    </div>
                </div>
            );
        }
    });
    
    ......
    
    #使用的示例
    var imageCtrl = new ImageCtrl();
    var imageDataStore = imageCtrl.findAll();
    ReactDOM.render(
        <div className="img-content card-mode">
            <ul className="js-img-list u-clearfix">
                {
                    imageDataStore.map(function (item,index) {
                        return <li key={item.id}><ImgListItemComponent imgData={item}/></li>
                    })
                }
            </ul>
        </div>,
        document.getElementById('imageList')
    );
    

    在React中,通过React.createClass方法就可以生成一个组件,通过这个方法,我们可以封装自己的组件,并且像普通的html标签一样在网页中插入。界面交互的大多数场景实现,就是在组织不同的组件,实现组件的复用和状态控制。对于组件,我们可以像普通的html标签一样,设置属性,然后通过this.props就可以读取对应的属性,不同于html标签的是,jsx的属性,支持所有js的数据类型而不是普通字符串。

    React组件的props可以通过定义变量的方式,在组建类的外部访问,var imgList = <ImgListItemComponent imgData={item}/>,然后读取imgList.props.imgData,但是官方建议不要在外部对props进行修改,因为这个是不可控的。

    React创新性的将组件看成是一个状态机,页面渲染的时候,根据state属性的初始状态来决定如何渲染,在组件有互动需要的时候,不同的交互会导致state的改变,从而触发重新渲染UI。这样的实现机制和Jquery的事件绑定机制,设计理念是完全不一样的。其中getInitialState返回的object会被赋值作为初始化的state。在交互过程中,如果有需要改变状态的时候,执行this.setState({fileContent:"",fileStatus:false,fileEntity:null});,在传入的对象中,制定的state对应的值就会改变,从而导致render中根据对应的state值来渲染。

    ......
    
    module.exports = React.createClass({
        getInitialState: function() {
            return {fileTip: "",fileName: "",fileStatus:false,fileEntity:null,clicked: false,fileContent:"",fileNameShow:""};
        },
        render:function(){
            if (this.state.clicked) {
                return (
                    <div className="simple-modal upload-modal">
                ...省略...
                    </div>
                );
            }else {
                return <div />;
            }
        }
    
    .......
    

    this.props和this.state都是组件类提供的属性,可以通过组件直接读取,他们的区别是,props是固定的属性,已经设定就不再变化,而state根据交互的需要会发生变化。

    React 使用驼峰命名规范的方式给组件绑定事件处理器。如果需要绑定点击事件,直接设置onClick就可以,onClick="{this.handleClick}"绑定成功,如果用户点击onClick就会调用React.createClass创建的对象中的handleClick函数,结合setState就可以动态的改变组件的状态,进而更新界面。

    开发这个应用的过程中,使用了mixin实现的弹窗组件,该组件通过在body的最后面添加一个div标签来实现弹窗;基本够用,接下来的学习中,还会深入的学习mixin和弹窗的实现。khan学院的React modal

    开发过程

    在开发的过程中,因为最终要将html代码拆分成不同的模块,实现整个功能的过程中,可能涉及多个场景,所以将不同的场景,分别以纯静态页面的方式实现,这样就可以快速的调整页面布局,拆分之后保留页面原型。

    保存图片的时候,存储格式是ImageData类,该类扮演了Schema的作用;图片通过File读取之后,以base64形式保存在sessionStorage中,保存的过程抽象成专门的模块,这样以后需要实现异步上传的时候,可以直接重新实现该模块。该模块使用mocha进行单元测试。

    /*图片存储数据结构Schema*/
    ImageData = function(initData){
        this.name = "";
        this.id = "";
        this.desc = "";
        this.url = "";
        this.visit = "";
        this.createTime = null;
        this.format = null;
        this.file = "";
        this.type = "";
    
        var dataTypeList = ImageData.getParamList();
        if(typeof initData == "object"){
            for(var key in dataTypeList){
                var keyName = dataTypeList[key];
                if(initData[keyName]){
                    this[keyName] = initData[keyName];
                }
            }
        }
    };
    ImageData.getParamList = function(){
        var dataTypeList = ["name","id","desc","url","visit","createTime","format","file","type"];
        return dataTypeList;
    };
    
    /*数据存储相关代码*/
    var DataHandler = {
        get:function(key,callback){
            if(typeof sessionStorage != "object"){
                return [];
            }
    
            var dataStr = sessionStorage.getItem(key);
            var keyData = [];
            if(dataStr){
                keyData = JSON.parse(dataStr);
            }
            typeof callback == "function" && callback(keyData);
            return keyData;
        },
        //以下代码省略
        ......
    
    

    预览地址:http://pages.liuwill.com/
    项目代码:https://github.com/liuwill/react-webpack-startup

    下载源代码之后,执行npm install安装需要的依赖包,然后按照顺序执行gulp任务,就可以启动静态服务器预览效果。

    相关文章

      网友评论

      本文标题:动手实践用Gulp+Webpack构建纯前端React应用

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