背景:
隨着互聯網世界的興起,web前端開發的方式越來越多,出現了很多種場景開發的前端架構體系,也對前端的要求日益增高,早已經不是靠一個JQuery.js來做前端頁面的時代了,而今移動端變化最大,近兩年出現了React-lite.js,Vue.js,ReactNative,Weex...等一些開發方式,早期移動web端大多數基於sea.js模塊化去開發,而我更傾向於組件化方式去開發,因為組件化的獨立性才是為后期業務擴展,降低代碼維護成本的最佳方案。
針對移動web端組件化,本人這次引用了古映傑開發的react-lite.js來做,具體用什么方式去做?我下面一一介紹。
首先什么是web組件化?
1.組:組合的方式
2.件:原子性質
本人的理解是根據業務場景和UED設計結合抽象出來具有獨立性、共用性及擴展性的Html+CSS+javascript的結合體。
什么是JSX?
參考http://www.cnblogs.com/kuailingmin/p/3996406.html
為什么用react.js組件化方式去做移動web端?
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的方式去做整體前端架構,這樣一來,對於前端組件化這塊多了很多好處。
- 可以使用npm下載很多js開發的工具包,豐富我們很多前端應用的開發
- 通過npm下載babel,對JSX的支持和es6的語法糖轉譯,我們就可以放心的去用es6的語法去寫react.js的代碼
- 通過node.js提供的ejs模版也不失SEO友好
- 不用擔心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端實現應用。