動(dòng)手實(shí)踐用Gulp+Webpack構(gòu)建純前端React應(yīng)用

最近構(gòu)思了一個(gè)練手項(xiàng)目偎谁,應(yīng)用react實(shí)現(xiàn)程序的邏輯肿男,從而進(jìn)一步學(xué)習(xí)React框架開(kāi)發(fā)。這次的例子是一個(gè)純前端的簡(jiǎn)單應(yīng)用纤房,模擬實(shí)現(xiàn)圖片上傳和展示功能纵隔。應(yīng)用中,使用sessionStorage存儲(chǔ)圖片數(shù)據(jù)炮姨,并且將sessionStorage中存儲(chǔ)的圖片數(shù)據(jù)捌刮,以列表的形式展示出來(lái)。

目錄結(jié)構(gòu)

用Webpack打包React應(yīng)用

Webpack 是一個(gè)前端資源加載/打包工具舒岸,只需要相對(duì)簡(jiǎn)單的配置就可以提供前端工程化需要的各種功能绅作。之前的例子中,對(duì)react的模塊化吁津,采用的是requirejs的AMD方式棚蓄,使用Webpack之后,我們就可以使用nodejs的commonjs方式編寫(xiě)模塊化的js代碼碍脏。通過(guò)webpack梭依,會(huì)將所有依賴的資源打包成一個(gè)單獨(dú)的bundle,包含應(yīng)用的邏輯代碼典尾,還有依賴的模塊役拴。

如果使用jsx格式編寫(xiě)混編的js和html代碼,還需要安裝相應(yīng)的loader钾埂,才能成功打包河闰,使用的是babel-loader科平。這里的loader除了jsx之外,根據(jù)需要姜性,還可以支持sass等其他格式瞪慧。

安裝相應(yīng)的npm依賴包

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

跟所有的應(yīng)用程序一樣,react也需要有一個(gè)入口點(diǎn)部念,webpack會(huì)從入口點(diǎn)開(kāi)始弃酌,對(duì)所有的依賴文件進(jìn)行打包,在webpack.config.js配置文件中儡炼,進(jìn)行相應(yīng)的配置妓湘;entry就是入口點(diǎn)

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構(gòu)建項(xiàng)目

為了開(kāi)發(fā)和調(diào)試方便,引入構(gòu)建工具gulp乌询,主要使用到的插件包括:gulp-connect榜贴、gulp-sassgulp-webpack妹田、gulp-uglify唬党。分別使用npm安裝對(duì)應(yīng)的模塊,npm install gulp --save-dev鬼佣。

項(xiàng)目開(kāi)發(fā)中初嘹,簡(jiǎn)單的實(shí)現(xiàn)了幾個(gè)Task,進(jìn)行項(xiàng)目打包和構(gòu)建沮趣。

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的組件

搭建好環(huán)境之后,react的使用非常方便坷随,把html根據(jù)需要拆分成不同的模塊就可以直接在jsx語(yǔ)法的代碼中混合編寫(xiě)房铭,ReactDom.render就可以把模版轉(zhuǎn)換成html代碼,并且把html模塊代碼嵌入到指定的dom對(duì)象中温眉,<代表往后是html代碼缸匪,當(dāng)作html解析,{代筆往后是js代碼类溢,當(dāng)作js解析凌蔬,需要注意的是,因?yàn)閏lass是關(guān)鍵字闯冷,所以需要把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中蛇耀,通過(guò)React.createClass方法就可以生成一個(gè)組件辩诞,通過(guò)這個(gè)方法,我們可以封裝自己的組件纺涤,并且像普通的html標(biāo)簽一樣在網(wǎng)頁(yè)中插入译暂。界面交互的大多數(shù)場(chǎng)景實(shí)現(xiàn)抠忘,就是在組織不同的組件,實(shí)現(xiàn)組件的復(fù)用和狀態(tài)控制外永。對(duì)于組件崎脉,我們可以像普通的html標(biāo)簽一樣,設(shè)置屬性伯顶,然后通過(guò)this.props就可以讀取對(duì)應(yīng)的屬性囚灼,不同于html標(biāo)簽的是,jsx的屬性砾淌,支持所有js的數(shù)據(jù)類型而不是普通字符串啦撮。

React組件的props可以通過(guò)定義變量的方式,在組建類的外部訪問(wèn)汪厨,var imgList = <ImgListItemComponent imgData={item}/>赃春,然后讀取imgList.props.imgData,但是官方建議不要在外部對(duì)props進(jìn)行修改劫乱,因?yàn)檫@個(gè)是不可控的织中。

React創(chuàng)新性的將組件看成是一個(gè)狀態(tài)機(jī),頁(yè)面渲染的時(shí)候衷戈,根據(jù)state屬性的初始狀態(tài)來(lái)決定如何渲染狭吼,在組件有互動(dòng)需要的時(shí)候,不同的交互會(huì)導(dǎo)致state的改變殖妇,從而觸發(fā)重新渲染UI刁笙。這樣的實(shí)現(xiàn)機(jī)制和Jquery的事件綁定機(jī)制,設(shè)計(jì)理念是完全不一樣的谦趣。其中g(shù)etInitialState返回的object會(huì)被賦值作為初始化的state疲吸。在交互過(guò)程中,如果有需要改變狀態(tài)的時(shí)候前鹅,執(zhí)行this.setState({fileContent:"",fileStatus:false,fileEntity:null});摘悴,在傳入的對(duì)象中,制定的state對(duì)應(yīng)的值就會(huì)改變舰绘,從而導(dǎo)致render中根據(jù)對(duì)應(yīng)的state值來(lái)渲染蹂喻。

......

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都是組件類提供的屬性,可以通過(guò)組件直接讀取捂寿,他們的區(qū)別是口四,props是固定的屬性,已經(jīng)設(shè)定就不再變化者蠕,而state根據(jù)交互的需要會(huì)發(fā)生變化窃祝。

React 使用駝峰命名規(guī)范的方式給組件綁定事件處理器。如果需要綁定點(diǎn)擊事件,直接設(shè)置onClick就可以粪小,onClick="{this.handleClick}"綁定成功大磺,如果用戶點(diǎn)擊onClick就會(huì)調(diào)用React.createClass創(chuàng)建的對(duì)象中的handleClick函數(shù),結(jié)合setState就可以動(dòng)態(tài)的改變組件的狀態(tài)探膊,進(jìn)而更新界面杠愧。

開(kāi)發(fā)這個(gè)應(yīng)用的過(guò)程中,使用了mixin實(shí)現(xiàn)的彈窗組件逞壁,該組件通過(guò)在body的最后面添加一個(gè)div標(biāo)簽來(lái)實(shí)現(xiàn)彈窗流济;基本夠用,接下來(lái)的學(xué)習(xí)中腌闯,還會(huì)深入的學(xué)習(xí)mixin和彈窗的實(shí)現(xiàn)绳瘟。khan學(xué)院的React modal

開(kāi)發(fā)過(guò)程

在開(kāi)發(fā)的過(guò)程中,因?yàn)樽罱K要將html代碼拆分成不同的模塊姿骏,實(shí)現(xiàn)整個(gè)功能的過(guò)程中糖声,可能涉及多個(gè)場(chǎng)景,所以將不同的場(chǎng)景分瘦,分別以純靜態(tài)頁(yè)面的方式實(shí)現(xiàn)蘸泻,這樣就可以快速的調(diào)整頁(yè)面布局,拆分之后保留頁(yè)面原型嘲玫。

保存圖片的時(shí)候悦施,存儲(chǔ)格式是ImageData類,該類扮演了Schema的作用去团;圖片通過(guò)File讀取之后抡诞,以base64形式保存在sessionStorage中,保存的過(guò)程抽象成專門的模塊土陪,這樣以后需要實(shí)現(xiàn)異步上傳的時(shí)候沐绒,可以直接重新實(shí)現(xiàn)該模塊。該模塊使用mocha進(jìn)行單元測(cè)試旺坠。

/*圖片存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)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;
};

/*數(shù)據(jù)存儲(chǔ)相關(guān)代碼*/
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;
    },
    //以下代碼省略
    ......

預(yù)覽地址:http://pages.liuwill.com/
項(xiàng)目代碼:https://github.com/liuwill/react-webpack-startup

下載源代碼之后,執(zhí)行npm install安裝需要的依賴包扮超,然后按照順序執(zhí)行g(shù)ulp任務(wù)取刃,就可以啟動(dòng)靜態(tài)服務(wù)器預(yù)覽效果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末出刷,一起剝皮案震驚了整個(gè)濱河市璧疗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馁龟,老刑警劉巖崩侠,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異坷檩,居然都是意外死亡却音,警方通過(guò)查閱死者的電腦和手機(jī)改抡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)系瓢,“玉大人阿纤,你說(shuō)我怎么就攤上這事∫穆” “怎么了欠拾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骗绕。 經(jīng)常有香客問(wèn)我藐窄,道長(zhǎng),這世上最難降的妖魔是什么酬土? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任荆忍,我火速辦了婚禮,結(jié)果婚禮上诺凡,老公的妹妹穿的比我還像新娘东揣。我一直安慰自己,他們只是感情好腹泌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布嘶卧。 她就那樣靜靜地躺著,像睡著了一般凉袱。 火紅的嫁衣襯著肌膚如雪芥吟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天专甩,我揣著相機(jī)與錄音钟鸵,去河邊找鬼。 笑死涤躲,一個(gè)胖子當(dāng)著我的面吹牛棺耍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播种樱,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蒙袍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了嫩挤?” 一聲冷哼從身側(cè)響起害幅,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岂昭,沒(méi)想到半個(gè)月后以现,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年邑遏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佣赖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡无宿,死狀恐怖茵汰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孽鸡,我是刑警寧澤蹂午,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站彬碱,受9級(jí)特大地震影響豆胸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巷疼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一晚胡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嚼沿,春花似錦估盘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至攀细,卻和暖如春箫踩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谭贪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工境钟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人俭识。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓慨削,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親套媚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子理盆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 在現(xiàn)在的前端開(kāi)發(fā)中,前后端分離凑阶、模塊化開(kāi)發(fā)、版本控制衷快、文件合并與壓縮宙橱、mock數(shù)據(jù)等等一些原本后端的思想開(kāi)始...
    Charlot閱讀 5,439評(píng)論 1 32
  • GitChat技術(shù)雜談 前言 本文較長(zhǎng),為了節(jié)省你的閱讀時(shí)間,在文前列寫(xiě)作思路如下: 什么是 webpack师郑,它要...
    蕭玄辭閱讀 12,689評(píng)論 7 110
  • 最近看了一本關(guān)于學(xué)習(xí)方法論的書(shū)环葵,強(qiáng)調(diào)了記筆記和堅(jiān)持的重要性。這幾天也剛好在學(xué)習(xí)React宝冕,所以我打算每天堅(jiān)持一篇R...
    gaoer1938閱讀 1,673評(píng)論 0 5
  • 一张遭、現(xiàn)代前端開(kāi)發(fā) 1.1 ES6 —— 新一代的JavaScript標(biāo)準(zhǔn) 1.1.1 語(yǔ)法特性 const、let...
    殺破狼real閱讀 1,839評(píng)論 0 3
  • 我發(fā)現(xiàn)秋葉大叔恰好每次都能在紅利期趕上潮流地梨,這應(yīng)該和秋葉大叔自己前期的累積和善于觀察有關(guān)菊卷,教主也提到過(guò)秋葉大叔對(duì)自...
    有錢YQ閱讀 912評(píng)論 0 0