React 基礎學習筆記
黑馬程序員視頻:傳送門
1. React 基礎
1.1 介紹react
React起源于Facebook的內部項目卜朗,
首先清楚兩個概念:
library(庫):小而巧的是庫苇侵,只提供了特定的API,如 jQuery历恐;庫的優(yōu)點是小巧方便寸癌,很方便的進行庫之間的切換,代碼沒有多大的改變弱贼;
Framework(框架):大而全的是框架蒸苇;框架提供的是一整套解決的方案;若在項目中切換不同框架吮旅,是比較困難的溪烤;
1.2.三大框架的現狀
三大框架互相抄;
Angular.Js:較早的前端框架庇勃,學習曲線較陡檬嘀,NG1學起來比較麻煩,NG2-NG5進行了一系列改革匪凉,引入了組件化的思維务唐,且支持TS編程父腕;
Vue.js:最火(關注最多)的前端框架役耕,中文文檔友好秽五;
React.js:最流行(使用最多)的前端框架,設計很優(yōu)秀聂受;
1.3.從組件化方面對比React和Vue
1.3.1 組件化方面
-
什么是模塊化蒿秦?
模塊化是從代碼的角度進行分析;
開發(fā)中把一些可復用的代碼抽離為整個的模塊蛋济,便于項目的維護開發(fā)棍鳖;
-
什么是組件化?
組件化是從UI界面的角度進行分析碗旅;
把一些可復用的UI元素(如輪播圖)抽離為單獨的組件渡处;
-
組件化的好處?
- 隨著項目規(guī)模的增大祟辟,組件就越來越多医瘫,組件化便于開發(fā)與維護;
-
Vue是如何實現組件化的旧困?
以
.vue
文件來創(chuàng)建對應的組件醇份,文件包含template結構 script行為 style樣式
結構稼锅;使用
Vue.component() 或 Vue.extends()
創(chuàng)建組件;
-
React是如何實現組件化的僚纷?
- React 中有組件化的概念矩距,但是和Vue中的組件模板文件不同,在React中一切都是以Js運行的怖竭,因此學習React锥债,JS必須要合格,熟悉使用ES6和ES7(async和await)侵状;
1.4.從其它角度對比React和Vue
1.4.1 開發(fā)團隊方面
React:由Facebook前端開發(fā)團隊維護和更新赞弥;,技術實力比較雄厚趣兄;
Vue:由尤雨溪的開發(fā)團隊進行開發(fā)和維護;
1.4.2 社區(qū)方面
React:誕生時間早悼嫉,社區(qū)很強大艇潭,一些常見的問題、坑戏蔑、最優(yōu)解決方案蹋凝、文檔、博客在社區(qū)中都可以方便找到总棵;
Vue:相對React小些鳍寂,可能有一些坑沒有踩過;
1.4.3 移動App體驗方面
React:結合ReactNative情龄,提供了無縫遷移到移動APP的開發(fā)體驗(RN用的最多且最火迄汛,許多大公司都在使用來開發(fā)手機App);
Vue:結合Weex技術骤视,提供了遷移到移動端APP開發(fā)的體驗(阿里的項目使用)鞍爱;
1.5.為什么要學習React
對比Angular.js,React更加優(yōu)秀专酗,一切基于JS并實現了組件化開發(fā)的思想睹逃;
開發(fā)團隊實力強大,不用擔心斷更的情況祷肯;
社區(qū)強大沉填,許多問題都有最優(yōu)解決方案;
提供了無縫轉接到ReactNative 上的開發(fā)體驗佑笋,擴展了我們的技術能力翼闹,增強核心競爭力;
很多大型企業(yè)都采用了React.js作為前端項目的技術選型允青;
1.6.介紹DOM和虛擬DOM的概念
1.6.1 虛擬DOM
-
DOM的本質是什么橄碾?
- DOM(文檔對象模型)是瀏覽器中的概念卵沉,用JS對象來表示頁面上的元素,并提供了操作DOM對象的API ;
-
什么是React中的虛擬DOM法牲?
- 虛擬DOM是框架中的概念史汗,是程序猿用JS對象來模擬頁面中的DOM元素和DOM嵌套關系;
-
為什么要實現虛擬DOM(目的)拒垃?
- 為了實現頁面中的DOM元素高效的更新停撞;
-
DOM和虛擬DOM的區(qū)別:
DOM:瀏覽器中提供的概念,用JS對象表示頁面上的元素悼瓮,提供操作DOM元素的API戈毒;
虛擬DOM:框架中的概念,由開發(fā)框架的程序員手動用JS對象模擬DOM元素及其嵌套關系横堡;本質就是使用JS對象模擬DOM元素和其嵌套關系埋市,其目的就是為了實現頁面元素的高效更新;
1.6.2 diff 算法(下方)
1.7.虛擬DOM的本質和目的
虛擬DOM的本質就是使用JS對象模擬DOM元素和其嵌套關系命贴,其目的就是為了實現頁面元素的高效更新道宅;
1.7.1 實際的列表排序案例進行分析
案例:實際需求,點擊列表的頭胸蛛,進行對應的表格數據的排序(table表格數據):
表格中的數據從哪兒來的:從數據庫中查詢回來的污茵;
這些查詢的數據存放位置:數據在瀏覽器的內存中存放,而且是以對象數組的形式表示的葬项;
這些數據是怎么渲染到頁面上的:
a. 手動
for循環(huán)
整個對象數組泞当,然后手動拼接字符串(+
號拼接符);b. 使用模板引擎民珍,如 art.template(與a方法實質一樣)襟士;
思考:上述的a、b方案有沒有性能上的問題穷缤?
如果用戶點擊了一列的表頭(如:時間排序從大到械蟹洹),做法是:
第一步津肛,觸發(fā)點擊事件章喉,把內存中的數組重新排序;
第二步身坐,排序完畢后秸脱,頁面還未更新,內存中對象數組是新的部蛇;
第三步摊唇,想辦法把更新的數據重新渲染到頁面中(判斷有沒有性能上的問題);
分析總結:上述方案只實現了將數據渲染到頁面中涯鲁,但是并沒有把性能做到最優(yōu)巷查;
如何才能把性能做到最優(yōu)有序?
- 按需渲染頁面(只重新渲染更新的數據對應的頁面元素)
- 如何實現按需渲染岛请?
理解DOM樹概念以及瀏覽器渲染DOM的相關知識旭寿;
獲取并對比內存中新的DOM樹和舊的DOM樹的區(qū)別,只更新改動的DOM元素崇败;
- 如何獲取到內存中的DOM樹盅称,從而實現DOM樹的對比?
- 分析:在瀏覽器中并沒有直接獲取DOM樹的API后室,因而無法拿到從瀏覽器內存中的DOM樹缩膝;
我們程序員可以手動模擬新舊兩顆DOM樹;
程序員如何手動模擬DOM樹岸霹?如何模擬一個DOM元素疾层?
- 使用JS模擬一個DOM元素;
<div id="myDiv" title= "標題" data-index= "0">
內容信息
<p>哈哈哈</p>
</div>
// 下面通過JS對象模擬了上面的DOM樹結構
var div = {
tagName: 'div',
attrs: {id: 'myDiv', title: '標題', 'data-index': '0'},
childrens: [
'內容信息',
{
tagName: 'p',
attrs: {},
childrens: [
'哈哈哈',
]
}
],
}
- 程序員手動模擬的這兩個新舊DOM樹贡避,就是React中的虛擬DOM的概念云芦;
1.7.2 虛擬DOM概念總結
虛擬DOM就是用JS對象形式來模擬頁面上的DOM嵌套關系;(虛擬DOM是以JS對象的形式存在的)
1.8.介紹Diff算法的概念
1.8.1 tree diff
把新舊兩顆DOM樹的每一層進行對比贸桶;當整顆DOM樹逐層對比完畢,則所需要被按需更新的元素必然能夠找到桌肴;
1.8.2 component diff
在每一層中進行的對比(tree diff)中皇筛,對比相應的組件級別的差別;若對比前后組件類型相同坠七,則暫時認為此組件不需要更新水醋;反之,會進行移除舊組件彪置,創(chuàng)建新組件拄踪,并追加到頁面上;
1.8.3 element diff
在進行組件對比的時候拳魁,若兩個組件的類型相同惶桐,則需要進行元素級別的對比;
1.9.webpack 4.x 最基本的使用步驟
1.9.1 使用webpack
創(chuàng)建React的項目的步驟
進入項目文件夾潘懊,初始化項目姚糊,執(zhí)行
npm init -y
指令,生成package.json
文件授舟;項目文件夾根目錄下救恨,創(chuàng)建
src
目錄(存放代碼),dist
目錄(項目打包的目錄)释树;進入
src
目錄肠槽,新建一個index.html
文件擎淤、index.js
入口文件;項目根目錄下進行安裝
webpack
打包工具秸仙,執(zhí)行npm install webpack -D
和npm install webpack-cli -D
(webpack 4.X以上需要裝腳手架);項目根目錄下新建一個
webpack.config.js
文件嘴拢,進行配置webpack打包
的信息,使用module.export= { mode: 'development' // 新增mode屬性(必填)筋栋,值為development或者production炊汤,production表示壓縮打包的main.js文件 }
,使用的是NodeJs語法弊攘,webpack基于Node構建抢腐,支持Node API 語法;注意:webpack 4.X
中的一個特性襟交,就是約定大于配置
的概念迈倍,默認的打包入口entry
的路徑就是src/index.js
,打包輸出的文件路徑是dist/main.js
捣域;
1.10.關于Node和Chrome之間的關系
1.10.1 module.export= {}
和 export default {}
的區(qū)別
module.export= {}
:是Node中的概念啼染,在webpack不能使用export default {}
進行替換;export default {}
:是ES6中向外導出的模塊的API焕梅,與之對應的是import ** from '標識符'
迹鹅;
1.10.2 哪些是Node支持的特性?
只要是Chrome里面支持的特性贞言,Node中就支持斜棚;因為NodeJs是基于Chrome V8引擎的JavaScript運行環(huán)境;可以使用babel
插件進行轉換后使用该窗;
1.11.webpack-dev-server的基本使用
1.11.1 安裝使用webpack-dev-server
進行自動編譯打包
安裝
webpack-dev-server
插件弟蚀,執(zhí)行npm i webpack-dev-server -D
指令;打開根目錄下的
package.json
文件酗失,在scripts
屬性中增加"dev": "webpack-dev-server"
執(zhí)行
npm run dev
指令义钉,進行打包編譯,并編譯不會退出规肴,只要代碼改變會自動進行編譯捶闸,此時項目文件運行在本地的環(huán)境中,在http://localhost:8080/
中查看奏纪,注意實時打包生成的main.js
文件位于根目錄下鉴嗤,實際是存放在內存中,并沒有替換dist
下的main.js
序调,可以看作是存在main.js
文件醉锅,所有在index.html
文件中導入的js<script src= "../dist/main.js"></script>
改為<script src= "/main.js"></script>
;可以在
package.json
文件中增加打包的其他信息发绢,如:"dev": "webpack-dev-server --open --port 3000 --hot --progress --compress --host 127.0.0.1"
webpack-dev-server
是將生成文件放在內存中硬耍,這樣速度很快垄琐,并且對磁盤影響小经柴;
1.12.配置 html-webpack-plugin 插件
1.12.1 html-webpack-plugin
插件作用
該插件能夠將項目代碼生成到內存中去狸窘,安裝使用步驟:
安裝插件,執(zhí)行
npm i html-webpack-plugin -D
指令坯认;打開根目錄下
webpack.config.js
文件翻擒,增加下面代碼:
const path= require('path');
// 導入 `html-webpack-plugin` 插件
const HtmlWebPackPlugin= require('html-webpack-plugin');
// 創(chuàng)建一個插件的實例對象
const htmlPlugin= new HtmlWebPackPlugin({
template: path.join(__dirname, './src/index.html'), // 源文件
filename: 'index.html' // 生成的內存中首頁的名稱
})
// 向外暴露一個打包的配置對象
module.export= {
mode: 'development', // 新增mode屬性(必填),值為development或者production牛哺,production表示壓縮打包的main.js文件
plugins: [
htmlPlugin
]
}
瀏覽器中會展示出打包的代碼的效果陋气,可以查看源碼進行分析代碼;
接下來還需要配置
babel
插件引润;
1.13.使用React渲染最基本的虛擬DOM到頁面上
1.13.1 React 的安裝和使用
安裝巩趁,執(zhí)行
npm i react react-dom -S
指令,其中react
專門用于創(chuàng)建組件和虛擬DOM淳附,組件的生命周期也在這個包中议慰;react-dom
專門進行DOM操作,其中最主要的應用場景就是ReactDOM.render()
;在
index.html
中奴曙,創(chuàng)建容器:<div id= "app"></div>
别凹;在入口文件
main.js
中導入包:
import React from 'react'
import ReactDOM from 'react-dom'
- 創(chuàng)建虛擬DOM元素:
// 創(chuàng)建虛擬DOM元素 <h1 title= "標題" id= "test">內容信息</h1>
// 第一個參數是字符串類型的參數,表示要創(chuàng)建的標簽的名稱洽糟;
// 第二個參數是對象類型的參數番川,表示創(chuàng)建的元素的屬性節(jié)點;
// 第三個參數是子節(jié)點
const myh1= React.createElement(
'h1',
{title: "標題", id: "test"},
'內容信息'
)
- 渲染虛擬DOM元素到頁面中:
// 第一個參數表示要渲染的虛擬DOM對象脊框;
// 第二個參數表示指定容器,注意此處放的是一個容器的DOM對象践啄,并不是直接放容器元素的id字符串
ReactDOM.render(myh1, document.getElementById("app"))
1.14.使用React.createElement實現虛擬DOM嵌套
1.14.1 測試使用React.createElement建立虛擬DOM代碼
// 創(chuàng)建虛擬DOM元素 <h1 title= "標題" id= "test">內容信息</h1>
// 第一個參數是字符串類型的參數浇雹,表示要創(chuàng)建的標簽的名稱;
// 第二個參數是對象類型的參數屿讽,表示創(chuàng)建的元素的屬性節(jié)點昭灵;
// 第三個參數是子節(jié)點
const myh1= React.createElement(
'h1',
{title: "標題", id: "test"},
'內容信息'
);
const mydiv= React.createElement(
'div',
null,
myh1
);
// 第一個參數表示要渲染的虛擬DOM對象;
// 第二個參數表示指定容器伐谈,注意此處放的是一個容器的DOM對象烂完,并不是直接放容器元素的id字符串
ReactDOM.render(mydiv, document.getElementById("app"))
1.14.2 使用babel
插件,直接寫HTML
代碼
渲染頁面中的DOM
結構诵棵,最好的方式就是寫HTML
代碼:
1.15.在React項目中啟用JSX語法
1.15.1 最基礎的JSX語法代碼
// 1.導入包
import React from 'react'
import ReactDOM from 'react-dom'
// 2.創(chuàng)建虛擬DOM元素(虛擬DOM就是使用JS對象形式表示DOM和DOM間的嵌套關系)
const mydiv= React.createElement('div', {id:'test', title:"標題信息"}, "我是div內容");
// 3.調用render函數進行渲染
ReactDOM.render(mydiv, document.getElementById('app'))
1.15.2 使用babel
插件抠蚣,直接寫HTML
代碼
// 1.導入包
import React from 'react'
import ReactDOM from 'react-dom'
// 2.創(chuàng)建虛擬DOM元素(虛擬DOM就是使用JS對象形式表示DOM和DOM間的嵌套關系)
// const mydiv= React.createElement('div', {id:'test', title:"標題信息"}, "我是div內容");
// HTML 是最優(yōu)秀的標記語言,直接使用下面格式編寫會報錯履澳,因而使用babel插件轉換下列的標簽嘶窄;
// 注意:這種在JS中混合寫入類似與 HTML 的語法怀跛,叫做JSX語法;符合XML規(guī)范的JS柄冲;
// JSX的本質還是在運行的時候吻谋,使用babel轉換成了 React.createElement() 形式來運行的
const mydiv2= <div id= "test" title= "標題信息" >我是div內容</div>
// 3.調用render函數進行渲染
ReactDOM.render(mydiv, document.getElementById('app'))
1.15.3 babel 插件的安裝使用
- 安裝
babel
插件:
# loader/plugin 插件
npm install babel-core babel-loader babel-plugin-transform-runtime -D
# 語法
npm install babel-react-env babel-preset-stage-0 -D
- 安裝能識別
jsx
語法的包:
npm install babel-preset-react -D
- 在
webpack.config.js
配置文件中配置第三方loader
的使用,在module.export= {...}
中加入下面代碼现横,是由于webpack只支持.js
結尾的文件漓拾,例如.vue .png
等文件是無法處理,此處的js
中包含的html
代碼webpack
也是無法處理戒祠,因而需要配置:
module: { // 所有的第三方模塊的配置規(guī)則
rules: [ // 第三方匹配規(guī)則
{test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件
]
}
- 添加
.babelrc
配置文件骇两,寫入下面內容:
{
"presets": ["env", "stage-0", "react"],
"plugins": ["transform-runtime"],
}
1.16.在JSX中書寫JS代碼
1.16.1 在JSX中混合寫入js表達式
在
jsx
語法中,要把JS代碼寫到{}
中去得哆,在{}
里面就是按照js
的寫法就行脯颜;區(qū)別于在Vue
中的插值表達式語法{{}}
雙大括號;
渲染數字贩据;
渲染字符串栋操;
渲染Boolean值;
為屬性綁定值饱亮;
渲染jsx元素矾芙;
渲染jsx元素數組(注意
key
的問題,key
屬性會在增刪數組的時候影響數組中選中的元素)近上;將普通字符串數組剔宪,轉為jsx數組并渲染到頁面上(兩種方法);
注意:JSX語法中必須符合XML的語法規(guī)則壹无,對于Html標簽來說必須是閉合或者自閉合標簽葱绒,如 <hr/>
1.17.將普通字符串數組,轉為jsx數組并渲染到頁面上
1.17.1 方法一:手動在外部進行for循環(huán)
import React from 'react'
import ReactDOM from 'react-dom'
const arrStr= = ['111', '222', '333'];
// 定義一個空數組斗锭,用于存放標簽
const result= [];
arrStr.forEach(item=> {
const temp= <h2>{item}</h2>;
result.push(temp)
})
// 調用render函數進行渲染
ReactDOM.render(
<div>
{result}
</div>
, document.getElementById('app')
)
1.17.2 方法二:直接在內部進行for循環(huán)地淀,使用map函數
import React from 'react'
import ReactDOM from 'react-dom'
const arrStr= = ['111', '222', '333'];
// 調用render函數進行渲染
ReactDOM.render(
<div>
{ arrStr.map(item => { return <h3>item</h3> }) }
</div>
, document.getElementById('app')
)
2. React 組件
2.1.演示Vue和React中key的作用
2.1.1 編程中對于JavaScript語句后面是否加分號的問題
必須加分號的情況:下一行的開頭是
[ ( + - /
五個符號之一,則該行末尾或下行開頭加分號岖是;
2.1.2 測試數組中key的作用
在React和Vue中的key
的作用完全相同帮毁;
項目根目錄下新建一個
test
目錄,新建Vue的測試文件test.html vue.js
豺撑;在
vue.js
中寫單頁面的代碼茶行,實現渲染一個數組的功能案狠,對于數組的每個元素能夠進行選中,也能夠對數組的元素進行增刪操作,測試沒有綁定key
時呻此,手動增(unshift()方法
)添加數組元素時會對與選擇的元素進行影響蔓搞;
總結:React 中使用map函數或者Vue中使用 v-for 循環(huán),若想保持數組元素的狀態(tài)(如:是否選中,Vue中動畫)跃巡,就一定要對key屬性進行綁定;在React中牧愁,需要把key添加給被forEach或map或for循環(huán)直接控制的元素素邪;
import React from 'react'
import ReactDOM from 'react-dom'
const arrStr= = ['111', '222', '333'];
// 調用render函數進行渲染
ReactDOM.render(
<div>
{ arrStr.map(item => { return <h3 key= { item.id }> item </h3> }) }
</div>
, document.getElementById('app')
)
2.2.關于jsx語法的注意事項
- 在JSX 中寫注釋:
多行注釋(推薦使用):
{/* 注釋的內容 */}
單行注釋:
{
// 注釋的內容
}
在JSX中的元素添加
class
類名:使用className
替代class
;其次猪半,使用htmlFor
替換label
標簽的for
屬性兔朦,兩者原因是由于class for
也是JavaScript中關鍵字,會出現沖突磨确;在JSX創(chuàng)建DOM的時候沽甥,所有的節(jié)點必須由唯一的根元素進行包裹,如
<div>...</div>
乏奥;在JSX語法中摆舟,標簽必須成對出現,如果是單標簽邓了,一定要自閉合恨诱,如
<hr/>
;
2.3.創(chuàng)建組件的第一種方式并為組件傳遞props數據
2.3.1 使用構造函數來創(chuàng)建組件骗炉,并為組件傳遞數據
import React from 'react'
import ReactDOM from 'react-dom'
// 第一種創(chuàng)建組件的方式照宝,注意組件的首字母必須有大寫,調用的時候也是大寫
function Hello (props) { // props 用于接收參數句葵,該屬性是只讀的(在Vue中該屬性也是只讀的厕鹃,不能被重新賦值)
// return null 表示此組件什么都不渲染
// return null
console.log('props:',props)
// 在組件中必須返回一個合法的 JSX 虛擬DOM元素
return <div>
這是 Hello 組件
-- {props.name}
-- {props.age}
-- {props.gender}
</div>
}
const dog = {
name: "大黃",
age: 5,
gender: "公"
}
// 調用render函數進行渲染
ReactDOM.render(
<div>
<Hello name= {dog.name} age= {dog.age} gender= {dog.gender} ></Hello>
</div>
, document.getElementById('app')
)
2.4.使用ES6的展開運算符簡化傳遞props數據的過程
一定要熟悉使用JavaScript的知識(ES5/6/7 語法知識);
2.4.1 使用ES6的展開運算符(...
)傳遞對象乍丈、數組數據
// 調用render函數進行渲染
ReactDOM.render(
<div>
{ /* <Hello name= {dog.name} age= {dog.age} gender= {dog.gender} ></Hello> */ }
<Hello {...dog}></Hello>
</div>
, document.getElementById('app')
)
2.5.將組件抽離為單獨的.jsx文件
將組件的代碼抽離到單獨的文件中剂碴,使用
export default xxx
暴露出去組件;使用
import xxx from '...'
需要導入組件轻专,不要省略后綴名汗茄;注意還需要在抽離出去的單獨文件中增加:
import React from 'react'
,是由于在抽離的文件中使用了JSX
的語法铭若;
2.6.配置webpack從而在導入組件的時候,省略.jsx后綴名
在
webpack.config.js
配置文件導出的對象中增加下面的代碼递览,注意是與module
平級:
resolve: {
extensions: ['.js', '.jsx', '.json'], // 表示這幾個文件的后綴名可以省略不寫
}
2.7.配置webpack設置根目錄
2.7.1 設置src代碼目錄為@
在
webpack.config.js
配置文件導出的對象中resolve
下面增加代碼叼屠,注意是與上面的extensions
平級:
resolve: {
extensions: ['.js', '.jsx', '.json'], // 表示這幾個文件的后綴名可以省略不寫
alias:{ // 表示別名
'@': path.join(__dirname, './src'), // 這樣 @ 符號就表示根目錄中src的這一層
},
}
2.8.class-創(chuàng)建類并通過constructor掛載實例屬性
2.8.1 ES6 中class的使用
// 1.普通的構造函數創(chuàng)建對象
function Person (name, age) {
this.name= name; // 通過new出來的實例的this掛載的屬性稱為實例屬性;
this.age= age;
}
const p1= new Person('大黑', '2')
console.log (p1)
// 2.使用class關鍵字創(chuàng)建類
class Animal {
// 這是類中的構造器绞铃,每個類中都有一個構造器镜雨,若不寫,也會默認有一個空的constructor構造器
// 構造器作用:使用new的時候默認執(zhí)行構造器constructor中的代碼
constructor () (name, age) {
this.name= name; // 實例屬性
this.age= age;
}
}
const p2= new Person('小灰', '1')
console.log (p2)
2.9.class-使用static創(chuàng)建靜態(tài)屬性
2.9.1 靜態(tài)屬性定義
通過構造函數直接訪問到的屬性稱為靜態(tài)屬性儿捧,直接給了構造函數荚坞,不是通過this進行掛載的挑宠;
2.9.2 靜態(tài)屬性使用
// 1.普通的構造函數創(chuàng)建對象
function Person (name, age) {
this.name= name; // 通過new出來的實例的this掛載的屬性稱為實例屬性;
this.age= age;
}
Person.info= 'aaa' // info屬性直接掛載給構造函數颓影,稱為靜態(tài)屬性
// 將實例方法掛載到Person的原型對象上
Person.prototype.say = function () {
console.log('這是Person的實例方法')
}
// 靜態(tài)方法各淀,實例的對象無法訪問該方法,只能通過 Person.show() 進行訪問诡挂,使用的少
Person.show= function () {
console.log('這是Person的靜態(tài)方法')
}
// 實例化一個對象
const p1= new Person('大黑', '2')
console.log(p1.name) // name 是 Person 的實例屬性
console.log(Person.info) // info 是 Person 的靜態(tài)屬性
Person.say() // say 是 Person 的實例方法
// 2.使用class關鍵字創(chuàng)建類
class Animal {
constructor () (name, age) {
this.name= name; // 實例屬性
this.age= age;
}
// 在class內部碎浇,通過static關鍵字修飾出來的屬性就是靜態(tài)屬性;
static info= 'hahh';
// 此處也是將實例方法掛載到Person的原型對象上
eating () {
console.log('這是Animal的實例方法')
}
// 靜態(tài)方法使用static關鍵字璃俗,使用的少
static playing () {
console.log('這是Animal的靜態(tài)方法')
}
}
const p2= new Person('小灰', '1')
console.log (p2)
console.log(p2.name) // name 是 Animal 的實例屬性
console.log(Animal.info) // info 是 Animal 的靜態(tài)屬性
p2.eating() // eating 是 Animal 的實例方法
2.10.class-實例方法和靜態(tài)方法(見上方)
2.11.class-總結class的基本用法和兩個注意點
注意點1:在class內部只能寫
構造器奴璃、靜態(tài)屬性、靜態(tài)方法城豁、實例方法
四種(實例屬性在構造器中)苟穆;注意點2:class關鍵字內部還是用原來的方法實現的,因此把class關鍵字稱為
語法糖
唱星;
2.13.class-使用extends實現子類繼承父類
2.13.1 代碼案例
class American {
constructor (name ,age) {
this.name= name;
this.age= age;
}
}
const a1= new American('sara', '21')
class China {
constructor (name ,age) {
this.name= name;
this.age= age;
}
}
const c1= new China('wang', '21')
// 上面由于兩個類的屬性相同雳旅,可以通過創(chuàng)建一個父類
class Person {
constructor (name ,age) {
this.name= name;
this.age= age;
}
}
// 在class類中使用extends關鍵字,實現子類繼承父類魏颓,如下:
class American2 extends Person {
}
class China2 extends Person {
}
const a2= new American2('jack', '21') // 會自動執(zhí)行父類中的構造函數
const c2= new China2('huang', '20')
2.14.class-子類訪問父類上的實例方法
2.14.1 代碼案例
// 創(chuàng)建一個父類
class Person {
// 子類會繼承父類的構造函數
constructor (name ,age) {
this.name= name;
this.age= age;
}
// 父類中的實例方法岭辣,作為公共的方法
say () {
console.log('say hello')
}
}
// 在class類中使用extends關鍵字,實現子類繼承父類甸饱,如下:
class American2 extends Person {
}
class China2 extends Person {
}
const a2= new American2('jack', '21') // 會自動執(zhí)行父類中的構造函數
a2.say() // 調用父類中的實例方法
const c2= new China2('huang', '20')
2.15.class-constructor構造器中super函數的使用說明
2.15.1 問題討論及代碼案例
-
為什么一定要在
constructor
中調用super()
?- 若一個子類通過
extends
關鍵字繼承了父類沦童,那么子類構造器函數constructor()
中,必須調用super()
- 若一個子類通過
-
super()
有什么作用叹话?-
super()
是一個函數偷遗,是父類的構造器,子類中的super()
就是父類中的構造器constructor()
的引用驼壶;
-
-
super()
中參數為空且沒有執(zhí)行的代碼時氏豌,實例的對象并不會繼承父類中的構造器函數中的實例屬性?-
super()
作為父類中的構造器constructor()
的引用热凹,因此必須需要傳遞參數泵喘,因而才能正確的調用父類中的構造器函數;
-
// 創(chuàng)建一個父類
class Person {
// 子類會繼承父類的構造函數
constructor (name ,age) {
this.name= name;
this.age= age;
}
// 父類中的實例方法般妙,作為公共的方法
say () {
console.log('say hello')
}
}
// 在class類中使用extends關鍵字纪铺,實現子類繼承父類,子類中實現構造器時碟渺,一定要加入`super()`方法并傳遞參數:
class China3 extends Person {
constructor (name ,age) {
super (name ,age)
}
}
const c3= new China3('huang', '20')
2.16.class-為子類掛載獨有的實例屬性和實例方法
2.16.1 代碼案例
// 創(chuàng)建一個父類
class Person {
// 子類會繼承父類的構造函數
constructor (name ,age) {
this.name= name;
this.age= age;
}
// 父類中的實例方法鲜锚,作為公共的方法
say () {
console.log('say hello')
}
}
// 在class類中使用extends關鍵字,實現子類繼承父類,子類中實現構造器時芜繁,一定要加入`super()`方法并傳遞參數旺隙,IdNumber參數是中國人獨有的,因而不能掛載到父類上:
class China3 extends Person {
constructor (name ,age, IdNumber) {
super (name ,age)
// 單獨在子類中使用this進行綁定骏令;注意在子類中蔬捷,this只能放在super()后面;
this.IdNumber= IdNumber;
}
}
const c3= new China3('li', '20', '513*********')
2.17.使用class關鍵字創(chuàng)建組件
2.17.1 基本的class創(chuàng)建組件的語法
// 使用class創(chuàng)建組件伏社,必須要自己的組件繼承自 React.Component
class 組件名稱 extends React.Component {
// 在組件內部抠刺,必須要這個 render() 函數,該函數的作用是渲染當前組件對應的虛擬DOM結構
render () {
// render() 函數必須返回合法的JSX虛擬DOM結構
return <di>這是class創(chuàng)建的組件</div>
}
}
創(chuàng)建了的實例在使用 ReactDOM.render()
的時候摘昌,作為標簽時相當于是使用new
了一個實例對象
2.17.2 兩種創(chuàng)建類的方法的對比
用
構造函數
創(chuàng)建的函數速妖,叫做無狀態(tài)組件
;用
class
創(chuàng)建的函數聪黎,叫做有狀態(tài)組件
罕容;-
什么狀況下使用
有/無狀態(tài)的組件
?-
有/無狀態(tài)的組件
的本質區(qū)別是:有無state
屬性稿饰;
-
2.18.為class創(chuàng)建的組件傳遞props參數并直接使用this.props來訪問
2.18.1 代碼案例
import React from 'react'
import ReactDOM from 'react-dom'
class Movie extends React.Component {
render () {
// 在class關鍵字創(chuàng)建的組件中锦秒,若想使用外部傳遞的`props`參數,直接使用`this.props.xxx`訪問
return <div>
// 注意在組件class內部喉镰,this表示當前組件的實例對象旅择;同時props中的屬性都是只讀的,不能重新賦值
這是Movie組件---{this.props.name}---{this.props.age}
</div>
}
}
const user= {
name: 'wang',
age: 22,
gender: '男'
}
// 調用render函數進行渲染
ReactDOM.render(
<div>
{ /* <Movie name= {user.name} age= {user.age}></Movie> */}
<Movie {...age}></Movie> { /* ES6簡寫的擴展對象的語法 */}
</div>
, document.getElementById('app')
)
2.19.介紹class創(chuàng)建的組件中this.state
2.19.1 兩種創(chuàng)建類的方法的對比
使用
class
關鍵字創(chuàng)建的組件具有自己的私有數據和生命周期函數侣姆,而使用function
函數創(chuàng)建的組件只有props
生真,沒有自己的私有數據和生命周期函數;
用
構造函數
創(chuàng)建的函數捺宗,叫做無狀態(tài)組件
柱蟀;用
class
創(chuàng)建的函數,叫做有狀態(tài)組件
蚜厉;什么狀況下使用
有/無狀態(tài)的組件
长已?
-
有/無狀態(tài)的組件
的本質區(qū)別是:有無state
屬性;
2.19.2 代碼案例
import React from 'react'
import ReactDOM from 'react-dom'
class Movie extends React.Component {
// 在自定義構造器的時候必須要調用 super()
constructor () {
super ()
// 只有在調用了super() 后才能使用this關鍵字
this.state= { // 這個this.state對象相當于Vue中的data(return {...})昼牛,其中的數據可讀可寫
msg: '我是class創(chuàng)建得Movie組件'
}
}
render () {
// 在class關鍵字創(chuàng)建的組件中术瓮,若想使用外部傳遞的`props`參數,直接使用`this.props.xxx`訪問
return <div>
// 注意在組件class內部贰健,this表示當前組件的實例對象胞四;同時props中的屬性都是只讀的,不能重新賦值
這是Movie組件---{this.props.name}---{this.props.age}
<h2>{ this.state.msg }</h2>
</div>
}
}
const user= {
name: 'wang',
age: 22,
gender: '男'
}
// 調用render函數進行渲染
ReactDOM.render(
<div>
{ /* <Movie name= {user.name} age= {user.age}></Movie> */}
<Movie {...age}></Movie> { /* ES6簡寫的擴展對象的語法 */}
</div>
, document.getElementById('app')
)
2.20.介紹有狀態(tài)組件和無狀態(tài)組件的區(qū)別
用
構造函數
創(chuàng)建的組件霎烙,叫做無狀態(tài)組件
;用
class
創(chuàng)建的組件,叫做有狀態(tài)組件
悬垃;
- 若一個組件需要有私有數據游昼,推薦使用
class
創(chuàng)建的組件;
- 什么狀況下使用
有/無狀態(tài)的組件
尝蠕?
-
有/無狀態(tài)的組件
的本質區(qū)別是:有無state
屬性烘豌;
- 組件中的
props
和state/data
之間的區(qū)別:
props中的數據都是外界傳過來的數據;
state/data中的數據都是組件私有的(通過Ajax獲取回來的數據一般都是私有數據)看彼;
props中的數據都是只讀的廊佩,不可復寫;
state/data中的數據都是可讀可寫靖榕;
2.21.評論列表案例-創(chuàng)建CmtList組件并渲染基本頁面結構
// 1. 導入包
import React from 'react'
import ReactDOM from 'react-dom'
// 2. 使用class關鍵字創(chuàng)建組件
class Cmtlist extends React.Component {
constructor () {
super ()
this.state= {
msg: '組件的state中的信息',
CommentList: [ // 評論列表數據
{id: '1', user: 'aaa', content: '內容111'},
{id: '2', user: 'bbb', content: '內容222'},
{id: '3', user: 'ccc', content: '內容333'},
]
}
}
render () {
return <div>
<h1>這是評論列表組件</h1>
{this.state.CommentList.map( (item) => {
<div key= {item.id}>
<h3>評論人:{item.user}</h3>
<p>評論內容:{item.content}</p>
</div>
})}
</div>
}
}
// 3. 使用ReactDOM.render渲染虛擬DOM到頁面中
ReactDOM.render(<div>
<Cmtlist></Cmtlist>
</div>, document.getElementById('app'))
2.22.評論列表案例-將評論Item項抽離為單獨的CmtItem組件
// 1. 導入包
import React from 'react'
import ReactDOM from 'react-dom'
// 使用function定義每個評論項小組件
function CmtItem (props) {
return <div>
<h3>評論人:{props.user}</h3>
<p>評論內容:{props.content}</p>
</div>
}
// 使用class關鍵字創(chuàng)建評論框大組件
class Cmtlist extends React.Component {
constructor () {
super ()
this.state= {
msg: '組件的state中的信息',
CommentList: [ // 評論列表數據
{id: '1', user: 'aaa', content: '內容111'},
{id: '2', user: 'bbb', content: '內容222'},
{id: '3', user: 'ccc', content: '內容333'},
]
}
}
render () {
return <div>
<h1>這是評論列表組件</h1>
{this.state.CommentList.map( (item) => {
<CmtItem {...item} key= {item.id}></CmtItem>
})}
</div>
}
}
// 3. 使用ReactDOM.render渲染虛擬DOM到頁面中
ReactDOM.render(<div>
<Cmtlist></Cmtlist>
</div>, document.getElementById('app'))
2.23.評論列表案例-將評論列表組件和評論項組件抽離為單獨的組件
關鍵點是使用export default
進行組件暴露出去标锄,再使用import xxx from '...'
進行組件的引入;
注意:在抽離出去的組件中茁计,按需添加導入import React from 'react'
和其關聯(lián)的子組件料皇;
2.24.評論列表案例-演示@符號替代相對路徑的好處
由于在抽離子組件的過程中,對于有父子包含關系的組件的導入時星压,需要注意引入的路徑的問題践剂,因而考慮使用絕對路徑進行子組件的導入;在webpack.config.js
配置文件導出的對象中resolve
下面的alias
屬性娜膘,使用@
符號表示src
代碼目錄逊脯,因而在項目中使用@
符號進行路徑信息導入;
3. React 樣式
3.1.在組件中使用style行內樣式并封裝樣式對象
3.1.1 代碼案例(上一天的評論組件案例代碼)
render () {
return <div>
{/* 注意:在JSX中竣贪,若設置行內樣式時军洼,不能為 style 設置 字符串的值,而是該 tyle= { {color: 'red'} } 這么寫贾富,
之前的css屬性中有連字符 - 時歉眷,需要用單引號包裹,或者寫成大寫字母颤枪;同時行內樣式中是數值類型的樣式汗捡,可以不用引號包裹,
而字符串類型的樣式值必須用引號包裹畏纲,見下方的代碼 */}
{/* <h1 style= "color: red">這是評論列表組件</h1> */}
<h1 style= { { color: 'red', fontSize: '14px', zIndex: 10 } }>這是評論列表組件</h1>
</div>
}
3.1.2 對樣式代碼進行封裝抽離
從JSX代碼中抽離代碼成一個樣式對象扇住;
對于多個抽離出來的各個樣式對象組成一個大的樣式對象;
對于大的樣式對象單獨提到一個樣式對象的JS文件中盗胀,通過
export default
進行導出艘蹋,import xxx from 'xxx'
進行導入;
3.2.使用css樣式表美化組件
3.2.1 使用 className 進行樣式的添加
項目使用
css
樣式文件步驟:
安裝
style-loader css-loader
插件:npm i style-loader css-loader -D
票灰;配置
webpack.config.js
文件中的module=>rules
增加下面的代碼:
rules: {
{test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 打包處理 css 樣式表的第三方loader女阀,順序是逆序宅荤,先是'css-loader'處理,再'style-loader'處理浸策;
}
- 在JSX代碼引入引入寫好的樣式文件冯键,使用
className
替代原來的class
引入對于的class樣式;
render () {
return <div>
{/* 此處的 title 是在導入的css文件中編寫的 class 樣式庸汗,導入通過 : import xxx from 'xxx.css' */}
<h1 className= "title">這是評論列表組件</h1>
</div>
}
3.3.演示React中使用普通 css 樣式表的作用域沖突問題
3.3.1 思考問題
- 問題1:引入的樣式文件只在該文件中生效嗎惫确?
- 經過測試發(fā)現,直接導入的css樣式表默認是會在整個項目(全局)都生效蚯舱,原因是由于樣式表沒有作用域改化;
- 問題2:Vue組件中中的樣式表是否也有樣式表沖突的問題,怎么解決呢枉昏?
- Vue中通過
<style scoped></style>
進行局部樣式設置陈肛;
- 問題3:React 中是否有和Vue 中一樣的
scoped
指令呢?
- React 中沒有指令的概念凶掰;
3.4.為普通樣式表通過 modules 參數啟用模塊化
3.4.1 啟用Css樣式表的模塊化功能
- 配置
webpack.config.js
文件中的module=>rules
的css文件的第三分loader增加參數燥爷,方式是通過問號增加參數,其中有個固定的參數 modules 表示為普通的css樣式表啟用模塊化懦窘,代碼如下:
rules: {
{test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件
{ test: /\.css$/, use: ['style-loader', 'css-loader?modules'] }, modules 參數只有 css-loader 才能使用
}
- 修改在通過
className
引入的樣式表的值需要進行修改前翎,使用的為引入的那個樣式對象的名加屬性名:className= {xxx.title}
注意:css模塊化只是針對類選擇器(className= {...})和ID(id={...})選擇器生效,對于普通的css標簽選擇器不會進行模塊化
3.5.使用localIdentName來自定義模塊化的類名
3.5.1 自定義模塊化樣式表的名字畅涂,可選的參數有:
[path] :表示樣式表相對于項目根目錄的路徑港华;
[name]:表示樣式表文件名稱;
[local]:表示樣式的類名定義名稱午衰;
[hash:length]:表示32位的hash值立宜,可選值小于32就行;
3.5.2 代碼案例
rules: {
{test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件
{ test: /\.css$/, use: [ 'style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]' ] },
}
3.6.通過local和global設置類名是否被模塊化
3.6.1 global 設置全局的class類
在css樣式表的文件中加入 :global()
臊岸,讓被包裹的類名不被模塊化橙数,而是作為全局使用,寫法如下:
:global(.red) {
color: red;
}
在同一個元素上增加兩個或多個類名方式可以是如下兩種:
<h1 className= { title + ' ' + 'red' }>這是評論列表組件</h1>
<h1 className= { [title, 'red'].join(' ') }>這是評論列表組件</h1>
3.6.2 local 設置局部的class類
在css樣式表的文件中加入 :local()
帅戒,讓被包裹的類名被模塊化灯帮,而是作為局部使用,與不寫的效果一直逻住,是默認的行為钟哥;
3.7.在項目中為scss或less文件啟用模塊化
3.7.1 導入第三方樣式,如 Bootstrap
安裝
Bootstrap
第三方插件瞎访,執(zhí)行npm i bootstrape@3.3.7 -S
指令腻贰;在項目的代碼中進行
Bootstrap
樣式代碼進行導入,如下:
// 引入的包為 node_modules 目錄中時扒秸,可以省略node_modules 目錄播演,直接以包名開始引入自己的模塊
import bootCss from 'bootstrap/dist/css/bootsrtap.css' // 引入Bootstrap包的代碼
- 根據當前的報錯提示信息發(fā)現冀瓦,webpack無法處理一些圖片文件,先下載第三方loader写烤,執(zhí)行
npm i url-loader file-loader -D
指令咕幻;再配置webpack.config.js
文件中的module=>rules
的參數增加代碼,重新啟動項目后生效:
rules: {
{test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件
{ test: /\.css$/, use: [ 'style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]' ] },
{test: /\.ttf|woff|woff2|eot|svg$/, use: [ 'url-loader' ]}, // 打包處理字體文件的loader
}
- 注意在使用的時候顶霞,對于樣式文件做了模塊化處理,使用的方式變?yōu)樯厦媸褂脤ο蟮男问绞褂?使用有點兒麻煩):
使用bootstrap中的按鈕的樣式 btn btn-pramery 锣吼,如下:
<button className= { [bootCss.btn, bootCss['btn-primary']].join(' ') }></button>
- 希望使用第三方的樣式文件Bootstrap的方式选浑,如下面這種樣式:
使用bootstrap中的按鈕的樣式 btn btn-pramery ,如下:
<button className= "btn btn-primary"></button>
- 發(fā)現第三方的樣式表都是以
.css
結尾玄叠,那么我們自己定義的樣式文件可以使用sass less stylus
來寫樣式文件古徒,因而配置樣式表的模塊化中,換為.scss .less .stylus
結尾的樣式文件進行模塊化處理读恃,先需要安裝這些樣式文件的第三方loader插件隧膘,scss
安裝執(zhí)行npm i saaa-loader node-sass -D
;再配置webpack.config.js
文件中的module=>rules
的參數寺惫,導入樣式改為import 'bootstrap/dist/css/bootsrtap.css'
測試驗證能夠正確使用:
rules: {
{ test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ }, // 千萬別忘記排除 node_modules中的文件
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.ttf|woff|woff2|eot|svg$/, use: [ 'url-loader' ] }, // 打包處理字體文件的loader
{ test: /\.scss$/, use: [ 'style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]', 'sass-loader'] } // 打包處理scss文件的loader
}
3.8.在React中為按鈕綁定點擊事件
3.8.1 React 的事件綁定機制
在React中的事件綁定機制中疹吃,事件名為駝峰式格式,事件的值是一個
Function
React中的事件處理函數的語法格式為
onClick= { function }
西雀,可以將該函數抽離出去萨驶,與render()
函數同級,如下:
render () {
return <div>
// 事件的值直接是一個function 匿名函數
<button onClick= { function () { console.log('按鈕點擊事件觸發(fā)') } }>按鈕</button>
// 注意此處函數引用不能給方法帶小括號艇肴,帶上小括號的意思是自執(zhí)行函數腔呜;不過目前看來參數是個問題
<button onClick= { this.myFunction }>按鈕</button>
</div>
}
// 這是一個實例方法
myFunction () {
console.log('按鈕點擊事件觸發(fā)')
}
- 用的最多的事件綁定形式為:(是由于箭頭函數是個匿名函數,注意this的指向就行)
render () {
return <div>
<button onClick= { () => this.myFunction('傳參') }>按鈕</button>
</div>
}
// 事件處理函數需要定義為一個箭頭函數再悼,然后復制給函數名稱
myFunction = (arg) => {
console.log( '按鈕點擊事件觸發(fā)核畴,參數為:'+ arg )
}
// 一個完整的構組件的代碼
import React from 'react'
export default class BindEvent extends React.Component {
construcroe () {
super ()
this.state= {
msg: 'hahaha',
}
}
render() {
return <div>
<button onClick= { () => this.show('參數1', '參數2') }>按鈕</button>
</div>
}
show = (arg1, arg2) => {
console.log( '觸發(fā)點擊事件--'+ arg1+ arg2 )
}
}
3.9.使用this.setState修改state上的數據
3.9.1 實現點擊按鈕,操作state中的數據
show = (arg1, arg2) => {
console.log( '觸發(fā)點擊事件--'+ arg1+ arg2 )
// React中冲九,使用setState()方法改變state中的數據狀態(tài)值谤草,并自動進行頁面重新渲染,而直接 this.state.msg 形式修改數據后不會重新渲染娘侍;
this.setState({
msg: '12345',
});
}
3.10.this.setState的兩個注意點
在
this.setState({})
中咖刃,只會把對應的數據狀態(tài)更新,而不會覆蓋其他的數據狀態(tài)憾筏;this.setState({})
中的代碼時異步執(zhí)行的嚎杨,若在this.setState({})
執(zhí)行完畢后,又想立即拿到最新值氧腰,不能使用this.state.msg
直接去取枫浙,而是使用this.setState({},callback)
刨肃,用回調函數來獲取最新的狀態(tài)值;
3.11.React中綁定文本框與State中的值
默認情況下箩帚,在React中真友,如果頁面的表單元素綁定了 state
上的數據的狀態(tài)值,那么每當 state
上的狀態(tài)值變換紧帕,必然會自動把最新的狀態(tài)值同步到頁面上:
單項數據綁定:狀態(tài)值變化->自動更新頁面數據盔然;
若是UI頁面的文本框內容變化時,需要將變化同步到 state
中去是嗜,此時React中沒有這種自動同步機制愈案,需要程序員手動監(jiān)聽文本框內容的變化 onChange
事件,在 onChange
事件中拿到最新的文本框的值(方案1:使用e
事件進行獲榷焯隆站绪;方案2:使用ref
屬性獲取元素 ),再通過手動調用 this.setState({})
手動把值同步到 state
中丽柿;
render() {
return <div>
<button onClick= { () => this.show('參數1', '參數2') }>按鈕</button>
{/* 若直接把文本框的 value 屬性恢准,綁定到了state 的數據狀態(tài)值,而不提供 onChange 處理函數甫题,
得到的文本框是一個只讀的文本框馁筐;當文本框綁定 value 值后,要么提供一個 readyOnly 坠非,要么提供
一個 onChange 處理函數 */}
{/* <input type= "text" style= { {width: '100%'} } value= {this.state.msg} readOnly /> */}
<input type= "text" style= { {width: '100%'} } value= {this.state.msg} onChange= { (e) => this.changeEvent(e) } ref= "txt" />
</div>
}
// 每當文本框內容變換時眯漩,必將會調用這個函數
changeEvent= (e) => {
console.log('文本框內容變換時觸發(fā)')
// 方案1:使用`e`事件進行獲取
// console.log(e.target.value)
// 方案2:使用`ref`屬性獲取元素
console.log(this.refs.txt.value)
// 調用 this.setState({ }) 改變 state 中的數據的狀態(tài)值
const newVal= e.target.value;
this.setState({
msg: newVal,
})
}
3.12.拓展-Vue中實例的生命周期
每個組件的實例,從 創(chuàng)建->運行->銷毀
這個過程中麻顶,這些事件就叫做組件的生命周期函數赦抖;分析對比 Vue
和 React
的生命周期函數辅肾;
3.12.2 Vue 組件的生命周期函數
參考Vue官方文檔中的Vue聲明周期函數的圖示進行分析:Vue生命周期圖示
3.12.2.1 Vue 組件的創(chuàng)建階段
Init Event & LifeCycle:初始化
Vue事件
和Vue的聲明周期函數
队萤;beforeCreate
:這是組件創(chuàng)建階段的第一個聲明周期函數,此時組件的data
和methods
以及頁面的DOM結構都還沒有初始化矫钓,因而什么都做不了要尔;Init injection & reactivity:初始化
data
和methods
中的數據和方法;created
:這個是組件創(chuàng)建階段的第二個生命周期函數新娜,此時組件的data
和methods
已經可用了赵辕,但是頁面還沒有渲染出效果來,因而在這個生命周期中常常會發(fā)起Ajax
請求概龄;Has 'el' option?:判斷傳入的Vue對象是否有
el
还惠,有的話就進行編譯控制區(qū)域的代碼;沒有的話就等待私杜,直到vm.$mounted(el)
手動渲染蚕键,也進行編譯控制區(qū)域的代碼 (把 data 上的數據拿到救欧,并解析執(zhí)行模板結構中的指令,當所有的指令解析完畢锣光,那么模板頁面就渲染到內存
中了笆怠,此時模板頁面還沒有掛載到頁面上,僅僅存放在內存中誊爹,因而用戶還看不到效果)蹬刷;beforMount
:這是組件創(chuàng)建階段的第三個聲明周期函數,此時模板結構在內存中已經編譯完成,還沒有真正渲染到頁面中,此時看到的只是模板頁面赁豆,沒有進行數據的渲染;Create vm.$el and replace 'el' with it:這一步正在把內存中渲染好的模板結構替換到頁面上;
mounted
:這個是組件創(chuàng)建階段的第四個生命周期函數兽赁,此時頁面已經真正的渲染好了状答,用戶已經可以看到真實的頁面數據;當這個生命周期函數執(zhí)行完刀崖,組件的創(chuàng)建階段
就完成了惊科,進入到了組件的運行階段
;若大家用到了一些第三方的UI插件亮钦,而且這些插件需要被初始化馆截,那么必須在mounted
中進行初始化插件;
3.12.2.2 Vue 組件的運行階段
按需根據 data
數據的變化蜂莉,有選擇性的執(zhí)行 0 到 N 次蜡娶;
beforUpdate
:在這個生命周期函數中,數據是最新的數據映穗,而在頁面中呈現出的數據還是舊數據窖张;Virtual DOM re-render and patch:這個階段是根據最新的
data
數據,重新渲染模板結構到內存中蚁滋,并把渲染好的模板結構替換到頁面上宿接;updated
:在這個生命周期函數中,頁面已經完成了更新辕录,data
數據是最新的睦霎,頁面中呈現的數據也是最新的;
3.12.2.3 Vue 組件的銷毀階段
beforeDestroy
:這個生命周期函數會在vm.$destroy()
被調用時觸發(fā)走诞,只是表示改組件即將被銷毀副女;此時組件還是可用的,比如其中的data
和methods
等數據方法蚣旱,可正常訪問肮塞;Teardown watchers ,child components and event listeners:執(zhí)行銷毀處理操作襟齿,清理
檢測器 子組件 事件監(jiān)聽器
;destroyed
:在這個生命周期函數中枕赵,組件已經完成銷毀猜欺,其中的data
和methods
等數據方法都不可訪問使用;
3.13.拓展-Vue中實例的生命周期2(見上方)
3.14.快速梳理React的組件生命周期函數圖
參考React官方文檔中的React生命周期函數的圖示進行分析:React生命周期圖示
3.14.1 React 組件的創(chuàng)建階段
永遠只執(zhí)行一次拷窜;
componentWillMount
:render
:componentDidMount
:
3.14.2 React 組件的運行階段
按需根據 props
屬性或 state
狀態(tài)的改變开皿,有選擇性的執(zhí)行 0 到多次;
componentWillReceiveProps
:shouldcomponentUpdate
:componentWillUpdate
:render
:componentDidUpdate
:
3.14.3 React 組件的銷毀階段
永遠只執(zhí)行一次篮昧;
-
componentWillUnmount
: