ReactJS簡(jiǎn)介
- React 起源于 Facebook 的內(nèi)部項(xiàng)目,因?yàn)樵摴緦?duì)市場(chǎng)上所有 JavaScript MVC(Model View Controller) 框架都不滿意,就決定自己寫一套,用來(lái)架設(shè) Instagram 的網(wǎng)站。做出來(lái)以后,發(fā)現(xiàn)這套東西很好用,就在2013年5月開(kāi)源了。
- 由于 React 的設(shè)計(jì)思想極其獨(dú)特,屬于革命性創(chuàng)新,性能出眾,代碼邏輯卻非常簡(jiǎn)單。所以,越來(lái)越多的人開(kāi)始關(guān)注和使用,認(rèn)為它可能是將來(lái) Web 開(kāi)發(fā)的主流工具。
庫(kù)(library)和框架(FrameWork):
庫(kù):小而輕巧,只提供特定Api;優(yōu)點(diǎn)是船小好調(diào)頭,可以很方便地從一個(gè)庫(kù)切換到另一個(gè)庫(kù)(如jQuery到Zepto),代碼幾乎不需要怎么改動(dòng)。
框架:大而全,提供一整套解決方案。項(xiàng)目從一個(gè)框架切換到另一個(gè)是比較困難的。
三大主流框架
Angluar:最早(出來(lái)得最早),在印度用得比較多
- 出來(lái)最早的前端框架,學(xué)習(xí)曲線比較陡,NG1學(xué)起來(lái)比較麻煩,NG2開(kāi)始,進(jìn)行了一系列的改革,也開(kāi)始啟用組件化了;在NG中,也支持使用TS(TypeScript)進(jìn)行編程;
Vue:最火(關(guān)注的人多),在中國(guó)用得比較多。對(duì)我我們來(lái)說(shuō),文檔要友好一些。
React:最流行(用的人多)在國(guó)外用得比較多,因?yàn)樗脑O(shè)計(jì)很優(yōu)秀。
React和Vue的對(duì)比
組件化方面:
- 什么是模塊化:是從代碼的角度來(lái)進(jìn)行分析的;把編程時(shí)候的業(yè)務(wù)邏輯,分割抽離到不同的模塊中來(lái)進(jìn)行開(kāi)發(fā),這樣能夠方便代碼的重用,便于項(xiàng)目的維護(hù)和開(kāi)發(fā);
- 什么是組件化: 是從 UI 界面的角度來(lái)進(jìn)行分析的;把一些可復(fù)用的UI元素,抽離為單獨(dú)的組件;隨著我們項(xiàng)目的開(kāi)發(fā),我們手里的組件會(huì)越來(lái)越多,到后面我們?nèi)绻獙?shí)現(xiàn)一個(gè)頁(yè)面,可能直接把現(xiàn)有的組件拿過(guò)來(lái)進(jìn)行拼接,就能快速得到一個(gè)完整的頁(yè)面, 這樣方便了UI元素的重用;組件是元素的集合體;
- 組件化的好處:隨著項(xiàng)目規(guī)模的增大,手里的組件越來(lái)越多;很方便就能把現(xiàn)有的組件,拼接為一個(gè)完整的頁(yè)面;
-
Vue是如何實(shí)現(xiàn)組件化的: 通過(guò)
.vue文件,來(lái)創(chuàng)建對(duì)應(yīng)的組件,一個(gè)包含以下三個(gè)部分;- template 結(jié)構(gòu)
- script 行為
- style 樣式
導(dǎo)入使用: import Home from './Home.vue'
瀏覽器不識(shí)別這樣的.vue文件,所以在運(yùn)行前,會(huì)把 .vue 預(yù)先編譯成真正的組件;
- React如何實(shí)現(xiàn)組件化:React實(shí)現(xiàn)組件化的時(shí)候,并沒(méi)有像.vue這樣的組件模板文件;而是直接使用JS代碼的形式,去創(chuàng)建任何你想要的組件。
- React全部使用JS來(lái)實(shí)現(xiàn)一個(gè)組件,也就是說(shuō):結(jié)構(gòu)、樣式、業(yè)務(wù)邏輯是混合在JS里面一起編寫出來(lái)的。
- 要學(xué)習(xí)React,JS要合格;ES6 和 ES7 (async 和 await) 要會(huì)用
移動(dòng)APP開(kāi)發(fā)體驗(yàn)比較:
- Vue,結(jié)合 Weex 這門技術(shù),提供了遷移到移動(dòng)端App開(kāi)發(fā)的體驗(yàn)(Weex,目前只是一個(gè)小的玩具, 并沒(méi)有很成功的大案例;都是阿里自己的項(xiàng)目在用)
- React,結(jié)合 ReactNative,也提供了無(wú)縫遷移到移動(dòng)App的開(kāi)發(fā)體驗(yàn)(RN用的最多,也是最火最流行的,大公司用得多);
為什么要學(xué)習(xí)React
- 和Angular1相比,React設(shè)計(jì)很優(yōu)秀,一切基于JS并且基于組件化開(kāi)發(fā)的思想;
- 開(kāi)發(fā)團(tuán)隊(duì)實(shí)力強(qiáng)悍,不必?fù)?dān)心斷更的情況;
- 社區(qū)強(qiáng)大,很多問(wèn)題都能找到對(duì)應(yīng)的解決方案;
- 提供了無(wú)縫轉(zhuǎn)到 ReactNative 上的開(kāi)發(fā)體驗(yàn),讓我們技術(shù)能力得到了拓展;增強(qiáng)了我們的核心競(jìng)爭(zhēng)力;
- 很多企業(yè)中,前端項(xiàng)目的技術(shù)選型采用的是React.js
React中幾個(gè)核心的概念
虛擬DOM(Virtual Document Object Model)
- DOM的本質(zhì)是什么:就是用JS表示的UI元素。瀏覽器中的概念,用JS對(duì)象來(lái)表示頁(yè)面上的UI元素,并提供了操作 DOM 對(duì)象的API;
- 什么是React中的虛擬DOM:是框架中的概念,是程序員用JS對(duì)象來(lái)模擬頁(yè)面上的 DOM 和 DOM嵌套;
- 為什么要實(shí)現(xiàn)虛擬DOM(虛擬DOM的目的):為了實(shí)現(xiàn)頁(yè)面中, DOM 元素的高效更新
-
DOM和虛擬DOM的區(qū)別:
- DOM:由瀏覽器中的JS提供功能,所以我們只能人為的使用瀏覽器提供的固定的API來(lái)操作DOM對(duì)象;
-
虛擬DOM:是框架中的概念,不是由瀏覽器提供的,而是程序員手動(dòng)模擬實(shí)現(xiàn)的,類似于瀏覽器中的DOM,但是有著本質(zhì)的區(qū)別。
- 本質(zhì): 用JS對(duì)象,來(lái)模擬DOM元素和嵌套關(guān)系;
-
目的:就是為了實(shí)現(xiàn)頁(yè)面元素的高效更新;
虛擬DOM的概念
Diff算法
- tree diff:新舊兩棵DOM樹(shù),逐層對(duì)比的過(guò)程,就是Tree Diff; 每當(dāng)我們從前到后,把整顆DOM逐層的節(jié)點(diǎn)對(duì)比完畢,必然能夠找到所有需要被按需更新的元素;
- component diff:在進(jìn)行Tree Diff的時(shí)候,每一層中,組件級(jí)別的對(duì)比,叫做 Component Diff;當(dāng)對(duì)比組件的時(shí)候,如果兩個(gè)組件的類型相同,則暫時(shí)認(rèn)為這個(gè)組件不需要被更新,如果組件的類型不同,則立即將舊組件移除,新建一個(gè)組件,替換到被移除的位置;
-
element diff:在進(jìn)行組件對(duì)比的時(shí)候,如果兩個(gè)組件類型相同,則需要進(jìn)行元素級(jí)別的對(duì)比,如果元素內(nèi)容不同,則進(jìn)行相應(yīng)的替換修改;
-key:key這個(gè)屬性,可以把 頁(yè)面上的 DOM節(jié)點(diǎn) 和 虛擬DOM中的對(duì)象,做一層關(guān)聯(lián)關(guān)系;
Diff算法圖
創(chuàng)建基本的webpack4.x項(xiàng)目
- 運(yùn)行
npm init -y快速初始化項(xiàng)目 - 在項(xiàng)目根目錄創(chuàng)建
src源代碼目錄和dist產(chǎn)品目錄(發(fā)布的產(chǎn)品所在目錄) - 在 src 目錄下創(chuàng)建
index.html - 使用 cnpm 安裝 webpack ,運(yùn)行
cnpm i webpack -D和cnpm i webpack-cli -D(開(kāi)發(fā)依賴)- 如何安裝
cnpm: 全局運(yùn)行npm i cnpm -g
- 如何安裝
- webpack.config.js配置:webpack 4.x 提供了 約定大于配置的概念;目的是為了盡量減少配置文件的體積;
- 默認(rèn)約定了:打包的入口是
src->index.js(新建一個(gè)index.js) - 打包的輸出文件是
dist->main.js - 4.x 中 新增了
mode選項(xiàng)(必選項(xiàng)),可選的值為:development和production; production模式會(huì)壓縮打包文件的格式。如果另外寫了配置,如指定entry:''(入口路徑),那么就會(huì)覆蓋默認(rèn)的約定
- 默認(rèn)約定了:打包的入口是
- 執(zhí)行打包
webpack,注意,如果執(zhí)行后報(bào)了Cannot find module 'webpack-cli'的提示,說(shuō)明需要全局安裝webpack-cli,命令行運(yùn)行npm i webpack-cli -g - 打包完畢后dist下自動(dòng)生成了打包文件main.js,將它手動(dòng)引入到index.html中
<script src="../dist/main.js"></script> - 安裝webpack-dev-server,
npm i webpack-dev-server -D,快速搭建本地運(yùn)行環(huán)境的工具。執(zhí)行它的命令即是webpack-dev-server,在package.json里做了如下配置后,可直接執(zhí)行npm run dev來(lái)替代
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server"
},
9.重新配置打包文件路徑,webpack-dev-server會(huì)幫助我們自動(dòng)編譯
webpack-dev-server打包好的main.js托管到了內(nèi)存中,所在在項(xiàng)目根目錄中看不到;出于性能上的考慮,不用反復(fù)讀取物理磁盤
但是我們可以認(rèn)為,在項(xiàng)目根目錄中,有一個(gè)不可見(jiàn)的main.js,然后直接在index.html中引入<script src="/main.js"></script>

webpack-dev-server幾個(gè)配置項(xiàng):
- --open是重新編譯后自動(dòng)打開(kāi)瀏覽器 --open firefox(瀏覽器名稱) 則自動(dòng)用火狐瀏覽器打開(kāi)
- --port 3000 是自定義端口
- --hot 熱更新
- --host 127.0.0.1 指定域名
- --progress 顯示打包的進(jìn)度
- --compress 開(kāi)啟gzip壓縮
"dev": "webpack-dev-server --open --port 3000 --hot --host 127.0.0.1 --progress --compress"
配置完執(zhí)行npm run dev,會(huì)用chorme自動(dòng)打開(kāi)http://127.0.0.1:3000/(注意:cnpm只能用來(lái)安裝包,其他操作都需要用npm來(lái)執(zhí)行)
- 安裝html-webpack-plugin來(lái)把頁(yè)面托管生成到內(nèi)存中
npm i html-webpack-plugin -D
在webpack-config.js中配置:
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin');//導(dǎo)入在內(nèi)存中自動(dòng)生成index頁(yè)面的插件
//創(chuàng)建一個(gè)html-webpack-plugin插件的實(shí)例對(duì)象
const htmlPlugin = new HtmlWebPackPlugin({
template: path.join(__dirname,'./src/index.html'),//源文件
filename: 'index.html' //生成在內(nèi)存中首頁(yè)的名字
})
module.exports = {
mode:'development',//development production
plugins:[
htmlPlugin
]
}
運(yùn)行后就打開(kāi)的http://127.0.0.1:3000/就顯示index.html的內(nèi)容了
在項(xiàng)目中使用 react
- 運(yùn)行
cnpm i react react-dom -S安裝包(生產(chǎn)依賴)- react: 專門用于創(chuàng)建組件和虛擬DOM的,同時(shí)組件的生命周期都在這個(gè)包中
- react-dom: 專門進(jìn)行DOM操作的,最主要的應(yīng)用場(chǎng)景,就是
ReactDOM.render()
- 在
index.html頁(yè)面中,創(chuàng)建容器:
<!--創(chuàng)建一個(gè)容器,將來(lái)用來(lái)渲染的虛擬DOM,將放到這個(gè)容器內(nèi)顯示-->
<div id="app"></div>
- index.js中,導(dǎo)入包:
import React from 'react'
import ReactDOM from 'react-dom'
- 創(chuàng)建虛擬DOM元素:
// 這是 創(chuàng)建虛擬DOM元素的 API <h1 title="啊,五環(huán)" id="myh1">你比四環(huán)多一環(huán)</h1>
//參數(shù)1:創(chuàng)建的元素類型,格式為字符串,表示元素的名稱
//參數(shù)2:是一個(gè)對(duì)象或null,表示當(dāng)前這個(gè)DOM元素的屬性
//參數(shù)3:子節(jié)點(diǎn)(包括其他虛擬DOM 或 文本子節(jié)點(diǎn))
//參數(shù)n:其他子節(jié)點(diǎn),即多個(gè)子節(jié)點(diǎn)就一直往后排,用‘,’隔開(kāi)
const myh1 = React.createElement('h1', { title: '啊,五環(huán)', id: 'myh1' }, '你比四環(huán)多一環(huán)')
- 渲染:
// 使用ReactDOM把虛擬DOM渲染到頁(yè)面上
//參數(shù)1:要渲染的虛擬DOM元素(React.createElement創(chuàng)建出來(lái)的)
//參數(shù)2:指定渲染到頁(yè)面上哪個(gè)容器,是DOM元素而不是選擇器,因此這里不能直接放容器元素的Id字符串,需要放一個(gè)容器的DOM對(duì)象
ReactDOM.render(myh1, document.getElementById('app'))
8. JSX語(yǔ)法
什么是JSX語(yǔ)法:就是符合 xml 規(guī)范的 JS 語(yǔ)法;(語(yǔ)法格式相對(duì)來(lái)說(shuō),要比HTML嚴(yán)謹(jǐn)很多)
-
如何啟用 jsx 語(yǔ)法?
-
安裝
babel插件- 運(yùn)行
npm i babel-loader(babel-loader:負(fù)責(zé)轉(zhuǎn)換)
npm i @babel/core -D
npm i @babel/plugin-proposal-object-rest-spread -D
npm i @babel/plugin-transform-runtime -D
npm i @babel/runtime -S
注意:這邊有個(gè)版本對(duì)應(yīng)問(wèn)題,否則npm run dev后會(huì)失敗
現(xiàn)在最新的babel-loader 是8.x版本的,要使用@babel/core,而不是babel-core了。而babel-loader 7.x對(duì)應(yīng)安裝babel-core 6.x。
下面同理:
- 運(yùn)行
安裝能夠識(shí)別轉(zhuǎn)換jsx語(yǔ)法的包
npm i @babel/preset-react -D-
根目錄下添加
.babelrc配置文件{ "presets": ["@babel/preset-env", "@babel/preset-react", "mobx"], "plugins": [ "@babel/plugin-proposal-object-rest-spread", "@babel/plugin-transform-runtime" ] } -
添加babel-loader配置項(xiàng):
module: { //要打包的第三方模塊 rules: [ //{ test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ } 等價(jià)于下面,?表示'x'是0個(gè)或者1個(gè) { test: /\.jsx?$/, use: 'babel-loader', exclude: /node_modules/ } ] }
-
jsx 語(yǔ)法的本質(zhì):并不是直接把 jsx 渲染到頁(yè)面上,而是 內(nèi)部先轉(zhuǎn)換成了 createElement 形式,再渲染的;
在 jsx 中寫入 js 表達(dá)式:在 jsx 語(yǔ)法中,要把 JS代碼寫到
{ }中。當(dāng)編譯引擎,在編譯jsx代碼的時(shí)候,如果遇到了<那么就把它當(dāng)作 HTML代碼去編譯,如果遇到了{}就把 花括號(hào)內(nèi)部的代碼當(dāng)作普通JS代碼去編譯;
let a = 10;//渲染數(shù)字
let str = '你好,中國(guó)';//渲染字符串
let boo = true;//布爾值加入表達(dá)式
let title = 'lala';//為屬性綁定值
const h1 = <h1>你真可愛(ài)</h1>//渲染jsx元素
const arr =[
<h2>這是h2</h2>,//這是js對(duì)象,不是html標(biāo)簽
<h3>這是h3</h3>
]//渲染jsx元素?cái)?shù)組
//將普通字符串?dāng)?shù)組,轉(zhuǎn)為jsx數(shù)組并渲染到頁(yè)面上【兩種方案】
const arrStr =['毛利蘭','柯南','灰原哀'];
//方案一
const nameArr= [];
arrStr.forEach(item=>{//forEach沒(méi)有返回值
const temp = <h5>{item}</h5>
nameArr.push(temp);
})
//數(shù)組的map方法,對(duì)數(shù)組的每一項(xiàng)做一個(gè)指定的操作,并返回一個(gè)新的數(shù)組,必須寫return
const resultArr = arrStr.map(item=>{
return item +'~~'
})
//當(dāng)我們需要在JSX控制的區(qū)域內(nèi)寫js表達(dá)式,則需要把JS代碼寫到{}中
ReactDOM.render(<div>
{a+2}<hr/>
{str}<hr/>
{boo?'條件為真':'條件為假'}<hr/>
<p title={title}></p>
{h1}
{arr}
<hr/>
{nameArr}
<hr/>
{arrStr.map(item=>{
return <h3>{item}</h3>
})}
<hr/>
{arrStr.map(item => <h3>{item+'1'}</h3>)}
</div>,document.getElementById('app'))
-
在 jsx 中 寫注釋:推薦使用
{ /* 這是注釋 */ };因?yàn)槿绻麑憜涡凶⑨?code>//``,}`要換行 -
為 jsx 中的元素添加class類名:必須使用
className替代class,因?yàn)?class在ES6中是一個(gè)關(guān)鍵字;同樣,必須用htmlFor替換label的for屬性 - 給元素綁定屬性的時(shí)候用
{變量}即可,如<p title={title}></p> - 在JSX創(chuàng)建DOM的時(shí)候,所有的節(jié)點(diǎn),必須有唯一的根元素進(jìn)行包裹;
- 在 jsx 語(yǔ)法中,標(biāo)簽必須成對(duì)出現(xiàn),如果是單標(biāo)簽,則必須自閉合!
當(dāng) 編譯引擎,在編譯JSX代碼的時(shí)候,如果遇到了
<那么就把它當(dāng)作 HTML代碼去編譯,如果遇到了{}就把 花括號(hào)內(nèi)部的代碼當(dāng)作 普通JS代碼去編譯;

