移動web端的react.js組件化方案

   背景javascript

       隨着互聯網世界的興起,web前端開發的方式愈來愈多,出現了不少種場景開發的前端架構體系,也對前端的要求日益增高,早已經不是靠一個JQuery.js來作前端頁面的時代了,而今移動端變化最大,近兩年出現了React-lite.js,Vue.js,ReactNative,Weex...等一些開發方式,早期移動web端大多數基於sea.js模塊化去開發,而我更傾向於組件化方式去開發,由於組件化的獨立性纔是爲後期業務擴展,下降代碼維護成本的最佳方案。css

   針對移動web端組件化,本人此次引用了古映傑開發的react-lite.js來作,具體用什麼方式去作?我下面一一介紹。html

    首先什麼是web組件化?前端

            1.組:組合的方式vue

            2.件:原子性質java

            本人的理解是根據業務場景和UED設計結合抽象出來具備獨立性、共用性及擴展性的Html+CSS+javascript的結合體。node

    什麼是JSX?react

            參考http://www.cnblogs.com/kuailingmin/p/3996406.htmlwebpack

    爲何用react.js組件化方式去作移動web端?es6

            1.讓代碼層邏輯獨立起來,儘可能不要出現有不少js文件存在關聯,這樣寫多了業務場景,後期維護成本提高,由於「蜘蛛網變大,變的密集了」

            2.利用react.js中生命週期來提高業務邏輯的擴展能力,用react.js中的Virtual DOM來提高頁面渲染的性能

            3.react.js也提供了對SEO友好的方式

            4.能跨多平臺開發,並能開發多種類型的前端場景,好比數據可視化,單頁面應用,網頁遊戲。。。

            5.rendering更新可達到60fps(60fps是動力也是壓力,由於它意味着只有16.7毫秒(1000 / 60)來繪製每一幀)

            6.可組合,可重用、可維護

            7.制定了獨有的代碼編寫規範,制約了代碼編寫結構不清晰,混亂的現象。

 

 而今隨着node.js環境開發的興起,咱們項目中也採用了node.js的方式去作總體前端架構,這樣一來,對於前端組件化這塊多了不少好處。

  1. 可使用npm下載不少js開發的工具包,豐富咱們不少前端應用的開發
  2. 經過npm下載babel,對JSX的支持和es6的語法糖轉譯,咱們就能夠放心的去用es6的語法去寫react.js的代碼
  3. 經過node.js提供的ejs模版也不失SEO友好
  4. 不用擔憂cpu主進程的膨脹,由於就node.js就一個主進程,不少個子進程。

 下面進入個人移動web方案主題:

      

 

      從上圖主要有幾個重要點:

             1.項目是在node.js環境中開發的

             2.從ejs模版返回出html字符串給瀏覽器渲染

             3.ejs模版中引用的js文件已是已react-lite方式打包後的並經過babel轉譯es6和jsx語法糖的壓縮版js

             4.css文件和js文件都放在CDN中的,經過ejs模版引入

             5.獲取數據經過ajax發送請求到node.js環境去調用對應的接口。

       

      先從用react.js方式作移動web端組件化開始,首先要明確一點,項目不是用react.js最終打包壓縮的js!作法是在編寫代碼方式上以react.js語法去寫,該怎麼建立組件,該怎麼處理父子組件之間的通訊,仍是react.js方式正常去寫,關鍵在最後生成壓縮js則經過react-lite來進行,若是純react.js打包壓縮文件體積仍是很大的,第一次加載性能上稍有影響,但加載完以後的UI操做卻很順暢,咱們曾經嘗試過純react.js來作一個移動web端的頻道頁,對於3G,4G 的移動用戶來講真的看不出什麼變化。

先來了解下react.js的組件化寫法,怎麼去建立一個react.js組件:

    1.在頁面要定義一個Html DOM來接收react.js定義的組件內容,例子中id爲mian的就是組件容器:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <div id="main"></div>
</body>
</html>

這裏咱們建立一個div並設置一個id 這個id就是咱們react組件要引用到的

2.看看js裏面怎麼去定義組件

import React from "react";
import ReactDom from "react-dom";

class Index extends React.Component{
    render(){
        return (
            <h1>Hello!</h1>
        )
    }
}

ReactDom.render(<Index />,document.getElementById("main"));

很直觀的看到3層定義,第一層先引用react.js的包,第二層class自定義一個react組件,第三層用ReactDom.render將渲染的組件內容綁定到對應的html dom元素中 去。

這就造成了react組件雛形,會點js一看都會很快明白。吐槽一下:若是這樣return  Html DOM都看不懂的話,只能說你不適合寫js。組件的雛形定義好了,接下來該怎麼辦呢?react提供了一些機制,這裏介紹2個最主要的特性,也是經常使用關鍵點,一個是生命週期,另外一個是虛擬DOM!

  React生命週期:

      在react.js中定義了一套生命週期的體現,這種形式是之前js框架中沒有的,react的生命週期給我傳遞一個很直觀的邏輯場景,從組件渲染以前到組件渲染以後,從第一次組件渲染到第二次組件渲染的生命週期變化,都分的頗有條理,還給我最大的感覺就是針對多種業務場景都能遊刃有餘的處理,生命週期真心很贊。感慨就到此,上圖:

     react.js生命週期分4種流程:

         1.首次渲染:

                 getDefaultProps

                 getInitialState

                 componentWillMount

                 render

                 componentDidMount

        2.當屬性props發生變化

             componentWillReceiveProps

             shouldComponentUpdate

             componentWillUpdate

             render

             componentDidUpdate

        3. 當狀態state發生變化

            shouldComponentUpdate

            componentWillUpdate

            render

            componentDidUpdate

         4.銷燬

             componentWillUnmount

有人直接看到會很懵,沒關係,下面對每一個函數作一個解釋,就會幫你很容易的理解了:

          getDefaultProps:組件建立以前會先調用,全局性只有一次性

          getInitialState:初始化組件狀態

          componentWillMount:組件渲染以前調用,在這裏能夠作一個對默認屬性,默認狀態,和組件渲染以前的邏輯操做

          render:渲染組件,此操做會生成一個虛擬DOM存在內存中

          componentDidMount:組件渲染以後的操做,根據業務場景而定,若是有操做在此函數中處理便可

          componentWillReceiveProps:當組件中的默認屬性props發生了變化,此方法被調用到

          shouldComponentUpdate:組件接收到新的props或者state的時候調用,此函數返回值決定着原來的組件結構是否從新渲染

          componentWillUpdate:組件第二次渲染以前調用

          componentDidUpdate:組件第二次渲染以後調用

          componentWillUnmount:組件銷燬時調用

這些都是react.js規範好的操做流程,從命名上能夠看出帶有"will"的函數都是在render以前調用,帶有"Did"都是在render以後調用,有個這樣一個形式,在操做組件UI或擴展業務場景方便了不少。看一下在代碼中是怎麼呈現組件生命週期定義的:

import React from "react";
import ReactDom from "react-dom";

class Index extends React.Component{
    getDefaultProps(){
        //初始化屬性
    }
    getInitialState(){
        //初始化狀態
    }
    componentWillMount(){
        //組件第一次渲染以前調用
    }
    componentWillReceiveProps(){
        //當初始化屬性發生變化調用
    }
    shouldComponentUpdate(){
        //組件接受到新屬性或者新狀態的時候調用
    }
    componentWillUpdate(){
        //第二次渲染以前調用
    }
    componentWillUnmount(){
        //銷燬操做,在真正組件刪除以前調用
    }
    render(){//渲染
        return (
            <h1>Hello!</h1>
        )
    }
    componentDidMount(){
        //渲染以後調用
    }
    componentDidUpdate(){
        //第二次渲染以後調用
    }
}

ReactDom.render(<Index />,document.getElementById("main"));

       接下來再看一個react.js核心虛擬DOM,這是react.js爲何能讓世界接收它的最重要緣由,react.js團隊獨創了這個革命性的想法,在如今有些js框架也開始加入虛擬DOM概念,好比vue.js2.0。在我對虛擬DOM的認知總結一句話:「就是用耍小聰明的手段簡化了瀏覽器對DOM重複渲染的操做,耍的漂亮!」;

React虛擬DOM:

       Virtual DOM是react的精髓,不只是頁面渲染性能提高,最主要的是對DOM一層抽象,這種方式顛覆了咱們對前端DOM渲染的觀念,可能在瀏覽器端開發感受不是很直觀,而在ReactNative中開發中,這層抽象的意義變大了,在app端開發沒有dom存在,而react這樣的方式能夠編譯OC組件或者安卓的組件。總結虛擬DOM幾個概念:

       1.react.js建立一個組件render以後生成一個虛擬dom(純粹的一個js數據結構)放在內存中

       2.若是react組件發生變化時,新的Virtual DOM和老的Virtual DOM進行對比,將變得部分批量更新到真實DOM裏面去

       3.老的方式若是DOM發生了變化,大多數是將頁面DOM元素從新刷新一邊以後數據也更新了,而虛擬dom想法是讓js模擬真實DOM結構,而後在js層面作先後對比,用這樣方式效率確定是很高的,js層面工做對比完成後,再改變真實DOM,這就是快的方式。

 

React-lite:

       上面是介紹了react.js中2大概念,就至關一個戰士一隻手握着劍(虛擬DOM),一隻手拿着盾(生命週期),有了這樣的裝備戰士纔可以衝進戰場去做戰。也瞭解了react組件的封裝。這樣正常開發就已這樣方式去寫代碼邏輯,最終還要通過webpack打包操做的,在這個打包過程當中用react-lite.js替換掉react.js,這樣既簡單,又減小了文件大小,並保持了生命週期和虛擬DOM主要機制。客觀的講也許不是首次加載最好的,但保證是操做UI最流暢,二次渲染最快的。react-lite最直接的解釋就是移動版react.js

體積小:

    
reat-lite與react區別:

    1.react.PropType方法棄用

    2.react.js可在服務端渲染,react-lite在瀏覽器端渲染

    3.爲了保證百分百的移植性,react-lite.js函數命名都和react.js保持一致

    4.保持react.js中的虛擬DOM,生命週期等機制

reat-lite用法:

      用法很簡單,快捷,只要在webpack中打包作一些小的操做便可,先上代碼看吧

var webpack = require('webpack');
//打包less插件
var ExtractTextPlugin = require('extract-text-webpack-plugin');
//這裏的'./css/bundle.css'設置打包地址
var ExtractLess = new ExtractTextPlugin('./css/bundle.css');
//打包多個文件插件
//var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var path = require('path');
module.exports = {
    entry:[
        './react/star/app.js'
    ],
    output:{
        path:'./zip/channels/star',
        filename:'star.pak.js'
    },
    module:{
        loaders:[
            {test: /\.js$/, exclude: /(node_modules|bower_components)/, loader: 'babel',query:{presets:['es2015','react']}},
            {test:/\.less$/,loader:ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")},
            //圖片文件使用 url-loader 來處理,小於8kb的直接轉爲base64
            { test: /\.(png|jpg)$/, loader: 'url-loader?q=8192'}

        ]
    },
    resolve:{
        extensions:['','.js'],
        alias:{
            'react':'react-lite',
            'react-dom':'react-lite'
        }
    },

    plugins:[
       ExtractLess,
        new webpack.optimize.UglifyJsPlugin({
            compress:{
                warnings:false
            },
            mangle:{
                except:['$super','$','exports','require']
            }
        })
    ]
};

在resolve中配置alias屬性,將react和react-dom所有跟換react-lite便可。一步實現react和react-lite的切換,注意webpack打包的時候會出現拋error的現象,

可是webpack提供了UglifyJsPlugin插件,幫咱們很好的處理了這種打包異常,具體介紹能夠看一下http://www.cnblogs.com/kuailingmin/p/5643658.html

 

  

 總結:

          一種技術二種方式,編寫代碼以react.js方式去作,打包用react-lite.js方式壓縮文件,簡化了js體積,實現了PC移植到移動web端的過程,成功將react.js原有的組件化方式保留並在移動web端實現應用。

相關文章
相關標籤/搜索