React 基礎學習筆記

React 基礎學習筆記

黑馬程序員視頻:傳送門

1. React 基礎

1.1 介紹react

React起源于Facebook的內部項目,Instagram交友網(wǎng)站;React設計思維及其獨特,屬于革命性創(chuàng)新,代碼邏輯卻非常簡單;

首先清楚兩個概念:

  • library(庫):小而巧的是庫,只提供了特定的API,如 jQuery;庫的優(yōu)點是小巧方便,很方便的進行庫之間的切換,代碼沒有多大的改變;

  • Framework(框架):大而全的是框架;框架提供的是一整套解決的方案;若在項目中切換不同框架,是比較困難的;

1.2.三大框架的現(xiàn)狀

三大框架互相抄;

  • 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是如何實現(xiàn)組件化的?

    • .vue文件來創(chuàng)建對應的組件,文件包含template結構 script行為 style樣式結構;

    • 使用Vue.component() 或 Vue.extends()創(chuàng)建組件;

  • React是如何實現(xiàn)組件化的?

    • 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

  1. 對比Angular.js,React更加優(yōu)秀,一切基于JS并實現(xiàn)了組件化開發(fā)的思想;

  2. 開發(fā)團隊實力強大,不用擔心斷更的情況;

  3. 社區(qū)強大,許多問題都有最優(yōu)解決方案;

  4. 提供了無縫轉接到ReactNative 上的開發(fā)體驗,擴展了我們的技術能力,增強核心競爭力;

  5. 很多大型企業(yè)都采用了React.js作為前端項目的技術選型;

1.6.介紹DOM和虛擬DOM的概念

1.6.1 虛擬DOM

  • DOM的本質是什么?

    • DOM(文檔對象模型)是瀏覽器中的概念,用JS對象來表示頁面上的元素,并提供了操作DOM對象的API ;
  • 什么是React中的虛擬DOM?

    • 虛擬DOM是框架中的概念,是程序猿用JS對象來模擬頁面中的DOM元素和DOM嵌套關系;
  • 為什么要實現(xiàn)虛擬DOM(目的)?

    • 為了實現(xiàn)頁面中的DOM元素高效的更新;
  • DOM和虛擬DOM的區(qū)別:

    • DOM:瀏覽器中提供的概念,用JS對象表示頁面上的元素,提供操作DOM元素的API;

    • 虛擬DOM:框架中的概念,由開發(fā)框架的程序員手動用JS對象模擬DOM元素及其嵌套關系;本質就是使用JS對象模擬DOM元素和其嵌套關系,其目的就是為了實現(xiàn)頁面元素的高效更新;

1.6.2 diff 算法(下方)

1.7.虛擬DOM的本質和目的

虛擬DOM的本質就是使用JS對象模擬DOM元素和其嵌套關系,其目的就是為了實現(xiàn)頁面元素的高效更新;

1.7.1 實際的列表排序案例進行分析

案例:實際需求,點擊列表的頭,進行對應的表格數(shù)據(jù)的排序(table表格數(shù)據(jù)):

  1. 表格中的數(shù)據(jù)從哪兒來的:從數(shù)據(jù)庫中查詢回來的;

  2. 這些查詢的數(shù)據(jù)存放位置:數(shù)據(jù)在瀏覽器的內存中存放,而且是以對象數(shù)組的形式表示的;

  3. 這些數(shù)據(jù)是怎么渲染到頁面上的:

  • a. 手動for循環(huán)整個對象數(shù)組,然后手動拼接字符串(+號拼接符);

  • b. 使用模板引擎,如 art.template(與a方法實質一樣);

  1. 思考:上述的a、b方案有沒有性能上的問題?

  2. 如果用戶點擊了一列的表頭(如:時間排序從大到小),做法是:

  • 第一步,觸發(fā)點擊事件,把內存中的數(shù)組重新排序;

  • 第二步,排序完畢后,頁面還未更新,內存中對象數(shù)組是新的;

  • 第三步,想辦法把更新的數(shù)據(jù)重新渲染到頁面中(判斷有沒有性能上的問題);

  1. 分析總結:上述方案只實現(xiàn)了將數(shù)據(jù)渲染到頁面中,但是并沒有把性能做到最優(yōu);

  2. 如何才能把性能做到最優(yōu)?

  • 按需渲染頁面(只重新渲染更新的數(shù)據(jù)對應的頁面元素)
  1. 如何實現(xiàn)按需渲染?
  • 理解DOM樹概念以及瀏覽器渲染DOM的相關知識;

  • 獲取并對比內存中新的DOM樹和舊的DOM樹的區(qū)別,只更新改動的DOM元素;

  1. 如何獲取到內存中的DOM樹,從而實現(xiàn)DOM樹的對比?
  • 分析:在瀏覽器中并沒有直接獲取DOM樹的API,因而無法拿到從瀏覽器內存中的DOM樹;
  1. 我們程序員可以手動模擬新舊兩顆DOM樹;

  2. 程序員如何手動模擬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: [

        '哈哈哈',

      ]

    }

  ],

}

  1. 程序員手動模擬的這兩個新舊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的項目的步驟

  1. 進入項目文件夾,初始化項目,執(zhí)行 npm init -y指令,生成package.json文件;

  2. 項目文件夾根目錄下,創(chuàng)建src目錄(存放代碼),dist目錄(項目打包的目錄);

  3. 進入src目錄,新建一個index.html文件、index.js入口文件;

  4. 項目根目錄下進行安裝webpack打包工具,執(zhí)行npm install webpack -Dnpm install webpack-cli -D (webpack 4.X以上需要裝腳手架);

  5. 項目根目錄下新建一個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進行自動編譯打包

  1. 安裝webpack-dev-server插件,執(zhí)行npm i webpack-dev-server -D指令;

  2. 打開根目錄下的package.json文件,在scripts屬性中增加"dev": "webpack-dev-server"

  3. 執(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>

  4. 可以在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 插件作用

該插件能夠將項目代碼生成到內存中去,安裝使用步驟:

  1. 安裝插件,執(zhí)行npm i html-webpack-plugin -D指令;

  2. 打開根目錄下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

  ]

}

  1. 瀏覽器中會展示出打包的代碼的效果,可以查看源碼進行分析代碼;

  2. 接下來還需要配置babel插件;

1.13.使用React渲染最基本的虛擬DOM到頁面上

1.13.1 React 的安裝和使用

  1. 安裝,執(zhí)行npm i react react-dom -S指令,其中react專門用于創(chuàng)建組件和虛擬DOM,組件的生命周期也在這個包中;react-dom專門進行DOM操作,其中最主要的應用場景就是ReactDOM.render();

  2. index.html中,創(chuàng)建容器:<div id= "app"></div>

  3. 在入口文件main.js中導入包:


import React from 'react'

import ReactDOM from 'react-dom'

  1. 創(chuàng)建虛擬DOM元素:

// 創(chuàng)建虛擬DOM元素 <h1 title= "標題" id= "test">內容信息</h1>

// 第一個參數(shù)是字符串類型的參數(shù),表示要創(chuàng)建的標簽的名稱;

// 第二個參數(shù)是對象類型的參數(shù),表示創(chuàng)建的元素的屬性節(jié)點;

// 第三個參數(shù)是子節(jié)點

const myh1= React.createElement(

  'h1',

  {title: "標題", id: "test"},

  '內容信息'

)

  1. 渲染虛擬DOM元素到頁面中:

// 第一個參數(shù)表示要渲染的虛擬DOM對象;

// 第二個參數(shù)表示指定容器,注意此處放的是一個容器的DOM對象,并不是直接放容器元素的id字符串

ReactDOM.render(myh1, document.getElementById("app"))

1.14.使用React.createElement實現(xiàn)虛擬DOM嵌套

1.14.1 測試使用React.createElement建立虛擬DOM代碼


// 創(chuàng)建虛擬DOM元素 <h1 title= "標題" id= "test">內容信息</h1>

// 第一個參數(shù)是字符串類型的參數(shù),表示要創(chuàng)建的標簽的名稱;

// 第二個參數(shù)是對象類型的參數(shù),表示創(chuàng)建的元素的屬性節(jié)點;

// 第三個參數(shù)是子節(jié)點

const myh1= React.createElement(

  'h1',

  {title: "標題", id: "test"},

  '內容信息'

);

const mydiv= React.createElement(

  'div',

  null,

  myh1

);

// 第一個參數(shù)表示要渲染的虛擬DOM對象;

// 第二個參數(shù)表示指定容器,注意此處放的是一個容器的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函數(shù)進行渲染

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函數(shù)進行渲染

ReactDOM.render(mydiv, document.getElementById('app'))

1.15.3 babel 插件的安裝使用

  1. 安裝 babel 插件:

# loader/plugin 插件

npm install babel-core babel-loader babel-plugin-transform-runtime -D

# 語法

npm install babel-react-env babel-preset-stage-0 -D

  1. 安裝能識別 jsx 語法的包:

npm install babel-preset-react -D

  1. 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中的文件

  ]

}

  1. 添加.babelrc 配置文件,寫入下面內容:

{

  "presets": ["env", "stage-0", "react"],

  "plugins": ["transform-runtime"],

}

1.16.在JSX中書寫JS代碼

1.16.1 在JSX中混合寫入js表達式

jsx語法中,要把JS代碼寫到{}中去,在{}里面就是按照js的寫法就行;區(qū)別于在Vue中的插值表達式語法 {{}}雙大括號;

  • 渲染數(shù)字;

  • 渲染字符串;

  • 渲染Boolean值;

  • 為屬性綁定值;

  • 渲染jsx元素;

  • 渲染jsx元素數(shù)組(注意key的問題,key屬性會在增刪數(shù)組的時候影響數(shù)組中選中的元素);

  • 將普通字符串數(shù)組,轉為jsx數(shù)組并渲染到頁面上(兩種方法);

注意:JSX語法中必須符合XML的語法規(guī)則,對于Html標簽來說必須是閉合或者自閉合標簽,如 <hr/>

1.17.將普通字符串數(shù)組,轉為jsx數(shù)組并渲染到頁面上

1.17.1 方法一:手動在外部進行for循環(huán)


import React from 'react'

import ReactDOM from 'react-dom'

const arrStr= = ['111', '222', '333'];

// 定義一個空數(shù)組,用于存放標簽

const result= [];

arrStr.forEach(item=> {

  const temp= <h2>{item}</h2>;

  result.push(temp)

})

// 調用render函數(shù)進行渲染

ReactDOM.render(

  <div>

    {result}

  </div>

  , document.getElementById('app')

)

1.17.2 方法二:直接在內部進行for循環(huán),使用map函數(shù)


import React from 'react'

import ReactDOM from 'react-dom'

const arrStr= = ['111', '222', '333'];

// 調用render函數(shù)進行渲染

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 測試數(shù)組中key的作用

在React和Vue中的key的作用完全相同;

  1. 項目根目錄下新建一個test目錄,新建Vue的測試文件test.html vue.js

  2. vue.js中寫單頁面的代碼,實現(xiàn)渲染一個數(shù)組的功能,對于數(shù)組的每個元素能夠進行選中,也能夠對數(shù)組的元素進行增刪操作,測試沒有綁定key時,手動增(unshift()方法)添加數(shù)組元素時會對與選擇的元素進行影響;

總結:React 中使用map函數(shù)或者Vue中使用 v-for 循環(huán),若想保持數(shù)組元素的狀態(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函數(shù)進行渲染

ReactDOM.render(

  <div>

    { arrStr.map(item => { return <h3 key= { item.id }> item </h3> }) }

  </div>

  , document.getElementById('app')

)

2.2.關于jsx語法的注意事項

  1. 在JSX 中寫注釋:
  • 多行注釋(推薦使用): {/* 注釋的內容 */}

  • 單行注釋:


{

  // 注釋的內容

}

  1. 在JSX中的元素添加class類名:使用className替代class;其次,使用htmlFor替換label標簽的for屬性,兩者原因是由于class for也是JavaScript中關鍵字,會出現(xiàn)沖突;

  2. 在JSX創(chuàng)建DOM的時候,所有的節(jié)點必須由唯一的根元素進行包裹,如 <div>...</div>

  3. 在JSX語法中,標簽必須成對出現(xiàn),如果是單標簽,一定要自閉合,如 <hr/>

2.3.創(chuàng)建組件的第一種方式并為組件傳遞props數(shù)據(jù)

2.3.1 使用構造函數(shù)來創(chuàng)建組件,并為組件傳遞數(shù)據(jù)


import React from 'react'

import ReactDOM from 'react-dom'

// 第一種創(chuàng)建組件的方式,注意組件的首字母必須有大寫,調用的時候也是大寫

function Hello (props) { // props 用于接收參數(shù),該屬性是只讀的(在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函數(shù)進行渲染

ReactDOM.render(

  <div>

    <Hello name= {dog.name} age= {dog.age} gender= {dog.gender} ></Hello>

  </div>

  , document.getElementById('app')

)

2.4.使用ES6的展開運算符簡化傳遞props數(shù)據(jù)的過程

一定要熟悉使用JavaScript的知識(ES5/6/7 語法知識);

2.4.1 使用ES6的展開運算符(...)傳遞對象、數(shù)組數(shù)據(jù)


// 調用render函數(shù)進行渲染

ReactDOM.render(

  <div>

    { /* <Hello name= {dog.name} age= {dog.age} gender= {dog.gender} ></Hello> */ }

    <Hello {...dog}></Hello>

  </div>

  , document.getElementById('app')

)

2.5.將組件抽離為單獨的.jsx文件

  1. 將組件的代碼抽離到單獨的文件中,使用export default xxx暴露出去組件;

  2. 使用import xxx from '...'需要導入組件,不要省略后綴名;

  3. 注意還需要在抽離出去的單獨文件中增加: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.普通的構造函數(shù)創(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)屬性定義

通過構造函數(shù)直接訪問到的屬性稱為靜態(tài)屬性,直接給了構造函數(shù),不是通過this進行掛載的;

2.9.2 靜態(tài)屬性使用


// 1.普通的構造函數(shù)創(chuàng)建對象

function Person (name, age) {

  this.name= name;  // 通過new出來的實例的this掛載的屬性稱為實例屬性;

  this.age= age;

}

Person.info= 'aaa'  // info屬性直接掛載給構造函數(shù),稱為靜態(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關鍵字內部還是用原來的方法實現(xiàn)的,因此把class關鍵字稱為 語法糖

2.13.class-使用extends實現(xiàn)子類繼承父類

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關鍵字,實現(xiàn)子類繼承父類,如下:

class American2 extends Person {

}

class China2 extends Person {

}

const a2= new American2('jack', '21')  // 會自動執(zhí)行父類中的構造函數(shù)

const c2= new China2('huang', '20')

2.14.class-子類訪問父類上的實例方法

2.14.1 代碼案例


// 創(chuàng)建一個父類

class Person {

  // 子類會繼承父類的構造函數(shù)

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

  // 父類中的實例方法,作為公共的方法

  say () {

    console.log('say hello')

  }

}

// 在class類中使用extends關鍵字,實現(xiàn)子類繼承父類,如下:

class American2 extends Person {

}

class China2 extends Person {

}

const a2= new American2('jack', '21')  // 會自動執(zhí)行父類中的構造函數(shù)

a2.say()  // 調用父類中的實例方法

const c2= new China2('huang', '20')

2.15.class-constructor構造器中super函數(shù)的使用說明

2.15.1 問題討論及代碼案例

  • 為什么一定要在 constructor中調用super()?

    • 若一個子類通過 extends關鍵字繼承了父類,那么子類構造器函數(shù)constructor()中,必須調用super()
  • super()有什么作用?

    • super()是一個函數(shù),是父類的構造器,子類中的super()就是父類中的構造器constructor()的引用;
  • super()中參數(shù)為空且沒有執(zhí)行的代碼時,實例的對象并不會繼承父類中的構造器函數(shù)中的實例屬性?

    • super()作為父類中的構造器constructor()的引用,因此必須需要傳遞參數(shù),因而才能正確的調用父類中的構造器函數(shù);

// 創(chuàng)建一個父類

class Person {

  // 子類會繼承父類的構造函數(shù)

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

  // 父類中的實例方法,作為公共的方法

  say () {

    console.log('say hello')

  }

}

// 在class類中使用extends關鍵字,實現(xiàn)子類繼承父類,子類中實現(xiàn)構造器時,一定要加入`super()`方法并傳遞參數(shù):

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 {

  // 子類會繼承父類的構造函數(shù)

  constructor (name ,age) {

    this.name= name;

    this.age= age;

  }

  // 父類中的實例方法,作為公共的方法

  say () {

    console.log('say hello')

  }

}

// 在class類中使用extends關鍵字,實現(xiàn)子類繼承父類,子類中實現(xiàn)構造器時,一定要加入`super()`方法并傳遞參數(shù),IdNumber參數(shù)是中國人獨有的,因而不能掛載到父類上:

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() 函數(shù),該函數(shù)的作用是渲染當前組件對應的虛擬DOM結構

  render () {

    // render() 函數(shù)必須返回合法的JSX虛擬DOM結構

    return <di>這是class創(chuàng)建的組件</div>

  }

}

創(chuàng)建了的實例在使用 ReactDOM.render() 的時候,作為標簽時相當于是使用new了一個實例對象

2.17.2 兩種創(chuàng)建類的方法的對比

  • 構造函數(shù)創(chuàng)建的函數(shù),叫做無狀態(tài)組件

  • class創(chuàng)建的函數(shù),叫做有狀態(tài)組件

  • 什么狀況下使用有/無狀態(tài)的組件

    • 有/無狀態(tài)的組件的本質區(qū)別是:有無state屬性;

2.18.為class創(chuàng)建的組件傳遞props參數(shù)并直接使用this.props來訪問

2.18.1 代碼案例


import React from 'react'

import ReactDOM from 'react-dom'

class Movie extends React.Component {

  render () {

  // 在class關鍵字創(chuàng)建的組件中,若想使用外部傳遞的`props`參數(shù),直接使用`this.props.xxx`訪問

    return <div>

      // 注意在組件class內部,this表示當前組件的實例對象;同時props中的屬性都是只讀的,不能重新賦值

      這是Movie組件---{this.props.name}---{this.props.age}

    </div>

  }

}

const user= {

  name: 'wang',

  age: 22,

  gender: '男'

}

// 調用render函數(shù)進行渲染

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)建的組件具有自己的私有數(shù)據(jù)和生命周期函數(shù),而使用function函數(shù)創(chuàng)建的組件只有props,沒有自己的私有數(shù)據(jù)和生命周期函數(shù);

  1. 構造函數(shù)創(chuàng)建的函數(shù),叫做無狀態(tài)組件

  2. class創(chuàng)建的函數(shù),叫做有狀態(tài)組件

  3. 什么狀況下使用有/無狀態(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 {...}),其中的數(shù)據(jù)可讀可寫

      msg: '我是class創(chuàng)建得Movie組件'

    }

  }

  render () {

  // 在class關鍵字創(chuàng)建的組件中,若想使用外部傳遞的`props`參數(shù),直接使用`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函數(shù)進行渲染

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ū)別

  1. 構造函數(shù)創(chuàng)建的組件,叫做無狀態(tài)組件

  2. class創(chuàng)建的組件,叫做有狀態(tài)組件

  • 若一個組件需要有私有數(shù)據(jù),推薦使用class創(chuàng)建的組件;
  1. 什么狀況下使用有/無狀態(tài)的組件
  • 有/無狀態(tài)的組件的本質區(qū)別是:有無state屬性;
  1. 組件中的 propsstate/data之間的區(qū)別:
  • props中的數(shù)據(jù)都是外界傳過來的數(shù)據(jù);

  • state/data中的數(shù)據(jù)都是組件私有的(通過Ajax獲取回來的數(shù)據(jù)一般都是私有數(shù)據(jù));

  • props中的數(shù)據(jù)都是只讀的,不可復寫;

  • state/data中的數(shù)據(jù)都是可讀可寫;

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: [  // 評論列表數(shù)據(jù)

        {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: [  // 評論列表數(shù)據(jù)

        {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屬性中有連字符 - 時,需要用單引號包裹,或者寫成大寫字母;同時行內樣式中是數(shù)值類型的樣式,可以不用引號包裹,

    而字符串類型的樣式值必須用引號包裹,見下方的代碼 */}

    {/* <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 樣式文件步驟:

  1. 安裝style-loader css-loader 插件:npm i style-loader css-loader -D

  2. 配置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'處理;

}

  1. 在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. 問題1:引入的樣式文件只在該文件中生效嗎?
  • 經(jīng)過測試發(fā)現(xiàn),直接導入的css樣式表默認是會在整個項目(全局)都生效,原因是由于樣式表沒有作用域;
  1. 問題2:Vue組件中中的樣式表是否也有樣式表沖突的問題,怎么解決呢?
  • Vue中通過 <style scoped></style>進行局部樣式設置;
  1. 問題3:React 中是否有和Vue 中一樣的 scoped 指令呢?
  • React 中沒有指令的概念;

3.4.為普通樣式表通過 modules 參數(shù)啟用模塊化

3.4.1 啟用Css樣式表的模塊化功能

  • 配置webpack.config.js文件中的module=>rules的css文件的第三分loader增加參數(shù),方式是通過問號增加參數(shù),其中有個固定的參數(shù) modules 表示為普通的css樣式表啟用模塊化,代碼如下:

rules: {

  {test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/}, // 千萬別忘記排除 node_modules中的文件

  { test: /\.css$/, use: ['style-loader', 'css-loader?modules'] },  modules 參數(shù)只有 css-loader 才能使用

}

  • 修改在通過className引入的樣式表的值需要進行修改,使用的為引入的那個樣式對象的名加屬性名:className= {xxx.title}

注意:css模塊化只是針對類選擇器(className= {...})和ID(id={...})選擇器生效,對于普通的css標簽選擇器不會進行模塊化

3.5.使用localIdentName來自定義模塊化的類名

3.5.1 自定義模塊化樣式表的名字,可選的參數(shù)有:

  • [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

  1. 安裝 Bootstrap 第三方插件,執(zhí)行 npm i bootstrape@3.3.7 -S 指令;

  2. 在項目的代碼中進行 Bootstrap 樣式代碼進行導入,如下:


// 引入的包為 node_modules 目錄中時,可以省略node_modules 目錄,直接以包名開始引入自己的模塊

import bootCss from 'bootstrap/dist/css/bootsrtap.css'  // 引入Bootstrap包的代碼

  1. 根據(jù)當前的報錯提示信息發(fā)現(xiàn),webpack無法處理一些圖片文件,先下載第三方loader,執(zhí)行npm i url-loader file-loader -D指令;再配置 webpack.config.js文件中的module=>rules的參數(shù)增加代碼,重新啟動項目后生效:

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

}

  1. 注意在使用的時候,對于樣式文件做了模塊化處理,使用的方式變?yōu)樯厦媸褂脤ο蟮男问绞褂?使用有點兒麻煩):

使用bootstrap中的按鈕的樣式 btn btn-pramery ,如下:

<button className= { [bootCss.btn, bootCss['btn-primary']].join(' ') }></button>

  1. 希望使用第三方的樣式文件Bootstrap的方式,如下面這種樣式:

使用bootstrap中的按鈕的樣式 btn btn-pramery ,如下:

<button className= "btn btn-primary"></button>

  1. 發(fā)現(xiàn)第三方的樣式表都是以.css結尾,那么我們自己定義的樣式文件可以使用sass less stylus來寫樣式文件,因而配置樣式表的模塊化中,換為.scss .less .stylus結尾的樣式文件進行模塊化處理,先需要安裝這些樣式文件的第三方loader插件,scss 安裝執(zhí)行npm i saaa-loader node-sass -D;再配置 webpack.config.js文件中的module=>rules的參數(shù),導入樣式改為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中的事件處理函數(shù)的語法格式為onClick= { function },可以將該函數(shù)抽離出去,與render()函數(shù)同級,如下:


render () {

  return <div>

    // 事件的值直接是一個function 匿名函數(shù)

    <button onClick= { function () { console.log('按鈕點擊事件觸發(fā)') } }>按鈕</button>

    // 注意此處函數(shù)引用不能給方法帶小括號,帶上小括號的意思是自執(zhí)行函數(shù);不過目前看來參數(shù)是個問題

    <button onClick= { this.myFunction }>按鈕</button>

  </div>

}

// 這是一個實例方法

myFunction () {

  console.log('按鈕點擊事件觸發(fā)')

}

  • 用的最多的事件綁定形式為:(是由于箭頭函數(shù)是個匿名函數(shù),注意this的指向就行)

render () {

  return <div>

    <button onClick= { () => this.myFunction('傳參') }>按鈕</button>

  </div>

}

// 事件處理函數(shù)需要定義為一個箭頭函數(shù),然后復制給函數(shù)名稱

myFunction = (arg) => {

  console.log( '按鈕點擊事件觸發(fā),參數(shù)為:'+ 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('參數(shù)1', '參數(shù)2') }>按鈕</button>

    </div>

  }

  show = (arg1, arg2) => {

    console.log( '觸發(fā)點擊事件--'+ arg1+ arg2 )

  }

}

3.9.使用this.setState修改state上的數(shù)據(jù)

3.9.1 實現(xiàn)點擊按鈕,操作state中的數(shù)據(jù)


  show = (arg1, arg2) => {

    console.log( '觸發(fā)點擊事件--'+ arg1+ arg2 )

    // React中,使用setState()方法改變state中的數(shù)據(jù)狀態(tài)值,并自動進行頁面重新渲染,而直接 this.state.msg 形式修改數(shù)據(jù)后不會重新渲染;

    this.setState({

      msg: '12345',

    });

  }

3.10.this.setState的兩個注意點

  • this.setState({})中,只會把對應的數(shù)據(jù)狀態(tài)更新,而不會覆蓋其他的數(shù)據(jù)狀態(tài);

  • this.setState({})中的代碼時異步執(zhí)行的,若在this.setState({})執(zhí)行完畢后,又想立即拿到最新值,不能使用this.state.msg直接去取,而是使用this.setState({},callback),用回調函數(shù)來獲取最新的狀態(tài)值;

3.11.React中綁定文本框與State中的值

默認情況下,在React中,如果頁面的表單元素綁定了 state 上的數(shù)據(jù)的狀態(tài)值,那么每當 state 上的狀態(tài)值變換,必然會自動把最新的狀態(tài)值同步到頁面上:

單項數(shù)據(jù)綁定:狀態(tài)值變化->自動更新頁面數(shù)據(jù);

若是UI頁面的文本框內容變化時,需要將變化同步到 state 中去,此時React中沒有這種自動同步機制,需要程序員手動監(jiān)聽文本框內容的變化 onChange 事件,在 onChange 事件中拿到最新的文本框的值(方案1:使用e事件進行獲取;方案2:使用ref屬性獲取元素 ),再通過手動調用 this.setState({})手動把值同步到 state 中;


  render() {

    return <div>

      <button onClick= { () => this.show('參數(shù)1', '參數(shù)2') }>按鈕</button>

      {/* 若直接把文本框的 value 屬性,綁定到了state 的數(shù)據(jù)狀態(tài)值,而不提供 onChange 處理函數(shù),

      得到的文本框是一個只讀的文本框;當文本框綁定 value 值后,要么提供一個 readyOnly ,要么提供

      一個 onChange 處理函數(shù) */}

      {/* <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>

  }

  // 每當文本框內容變換時,必將會調用這個函數(shù)

  changeEvent= (e) => {

    console.log('文本框內容變換時觸發(fā)')

    // 方案1:使用`e`事件進行獲取

    // console.log(e.target.value)

    // 方案2:使用`ref`屬性獲取元素

    console.log(this.refs.txt.value)

    // 調用 this.setState({ }) 改變 state 中的數(shù)據(jù)的狀態(tài)值

    const newVal= e.target.value;

    this.setState({

      msg: newVal,

    })

  }

3.12.拓展-Vue中實例的生命周期

每個組件的實例,從 創(chuàng)建->運行->銷毀 這個過程中,這些事件就叫做組件的生命周期函數(shù);分析對比 VueReact 的生命周期函數(shù);

3.12.2 Vue 組件的生命周期函數(shù)

參考Vue官方文檔中的Vue聲明周期函數(shù)的圖示進行分析:Vue生命周期圖示

3.12.2.1 Vue 組件的創(chuàng)建階段

  1. Init Event & LifeCycle:初始化Vue事件Vue的聲明周期函數(shù)

  2. beforeCreate:這是組件創(chuàng)建階段的第一個聲明周期函數(shù),此時組件的datamethods以及頁面的DOM結構都還沒有初始化,因而什么都做不了;

  3. Init injection & reactivity:初始化datamethods中的數(shù)據(jù)和方法;

  4. created:這個是組件創(chuàng)建階段的第二個生命周期函數(shù),此時組件的datamethods已經(jīng)可用了,但是頁面還沒有渲染出效果來,因而在這個生命周期中常常會發(fā)起 Ajax 請求;

  5. Has 'el' option?:判斷傳入的Vue對象是否有el,有的話就進行編譯控制區(qū)域的代碼;沒有的話就等待,直到vm.$mounted(el)手動渲染,也進行編譯控制區(qū)域的代碼 (把 data 上的數(shù)據(jù)拿到,并解析執(zhí)行模板結構中的指令,當所有的指令解析完畢,那么模板頁面就渲染到內存中了,此時模板頁面還沒有掛載到頁面上,僅僅存放在內存中,因而用戶還看不到效果);

  6. beforMount:這是組件創(chuàng)建階段的第三個聲明周期函數(shù),此時模板結構在內存中已經(jīng)編譯完成,還沒有真正渲染到頁面中,此時看到的只是模板頁面,沒有進行數(shù)據(jù)的渲染;

  7. Create vm.$el and replace 'el' with it:這一步正在把內存中渲染好的模板結構替換到頁面上;

  8. mounted:這個是組件創(chuàng)建階段的第四個生命周期函數(shù),此時頁面已經(jīng)真正的渲染好了,用戶已經(jīng)可以看到真實的頁面數(shù)據(jù);當這個生命周期函數(shù)執(zhí)行完,組件的創(chuàng)建階段就完成了,進入到了組件的運行階段;若大家用到了一些第三方的UI插件,而且這些插件需要被初始化,那么必須在mounted中進行初始化插件;

3.12.2.2 Vue 組件的運行階段

按需根據(jù) data 數(shù)據(jù)的變化,有選擇性的執(zhí)行 0 到 N 次;

  1. beforUpdate:在這個生命周期函數(shù)中,數(shù)據(jù)是最新的數(shù)據(jù),而在頁面中呈現(xiàn)出的數(shù)據(jù)還是舊數(shù)據(jù);

  2. Virtual DOM re-render and patch:這個階段是根據(jù)最新的 data 數(shù)據(jù),重新渲染模板結構到內存中,并把渲染好的模板結構替換到頁面上;

  3. updated:在這個生命周期函數(shù)中,頁面已經(jīng)完成了更新,data數(shù)據(jù)是最新的,頁面中呈現(xiàn)的數(shù)據(jù)也是最新的;

3.12.2.3 Vue 組件的銷毀階段

  1. beforeDestroy:這個生命周期函數(shù)會在 vm.$destroy()被調用時觸發(fā),只是表示改組件即將被銷毀;此時組件還是可用的,比如其中的datamethods等數(shù)據(jù)方法,可正常訪問;

  2. Teardown watchers ,child components and event listeners:執(zhí)行銷毀處理操作,清理 檢測器 子組件 事件監(jiān)聽器

  3. destroyed:在這個生命周期函數(shù)中,組件已經(jīng)完成銷毀,其中的datamethods等數(shù)據(jù)方法都不可訪問使用;

3.13.拓展-Vue中實例的生命周期2(見上方)

3.14.快速梳理React的組件生命周期函數(shù)圖

參考React官方文檔中的React生命周期函數(shù)的圖示進行分析:React生命周期圖示

3.14.1 React 組件的創(chuàng)建階段

永遠只執(zhí)行一次;

  1. componentWillMount

  2. render

  3. componentDidMount

3.14.2 React 組件的運行階段

按需根據(jù) props 屬性或 state 狀態(tài)的改變,有選擇性的執(zhí)行 0 到多次;

  1. componentWillReceiveProps

  2. shouldcomponentUpdate

  3. componentWillUpdate

  4. render

  5. componentDidUpdate

3.14.3 React 組件的銷毀階段

永遠只執(zhí)行一次;

  1. componentWillUnmount
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • 從零搭建React全家桶框架教程筆記(一) 傳送門:從零搭建React全家桶框架教程 目錄 寫在前面 | 說明...
    Haleng閱讀 6,956評論 2 8
  • ReactJs小書筆記(一) ReactJs小書官方文檔:傳送門 1 react簡介 React.js 不是一個框...
    Haleng閱讀 694評論 0 0
  • React組件學習筆記——慕課網(wǎng) React組件慕課網(wǎng)視頻:傳送門 第1章 初識React 1.1 React基本...
    Haleng閱讀 564評論 0 0
  • [toc] REACT react :1.用來構建用戶界面的 JAVASCRIPT 庫2.react 專注于視圖層...
    撥開云霧0521閱讀 1,461評論 0 1
  • RAC有一個主要的優(yōu)點,就是提供一個單一的,統(tǒng)一的方法去處理異步的行為,包括delegate方法,blocks回調...
    csp閱讀 256評論 0 0