一、react中的虛拟DOM
- react中元件化是直接使用js實作,vue中通過
實作;
.vue檔案
- 在vue中模闆
;
template(模闆結構)->ast(普通對象)->render函數(帶變量的函數對象)->虛拟dom(指派的函數對象)
- 在react中直接
;
js->虛拟dom
- 使用虛拟dom,頁面源碼中是沒有相應的dom标簽,頁面中元素都來自于引入的js檔案;浏覽器也不用解析相應html元素,直接解析js,形成真正的dom。
- 與vue:react中挂載是嵌套在
中;vue是直接替換;import引入時,都是将子元件檔案以對象鍵值對形式導入,不同的是react中jsx文法會被解析;但是生命周期都還是沒有開始;
index.html的#app
- vue是在父元件
開始子元件的生命周期,通過解析子元件标簽觸發的元件生命周期;react也是,在解析到子元件标簽後才開始子元件的生命周期。
beforeMount周期後
- ** react中引入時子元件render函數中jsx文法已經被解析,但createElement()中值也是變量存在,因為生命周期還沒有開始;vue中引入子元件是隻是元件檔案的對象形式(不是元件對象),生命周期也沒有開始,加載時子元件render函數要在挂載階段與自身Vue執行個體結合才把render函數中變量指派,然後執行render函數,傳回h(具體值/),這個執行完就是虛拟dom;**
- DOM
-
:就是指用js對象表示的UI元素;是浏覽器在記憶體中形成的很複雜的對象;本質
-
:隻不過是浏覽器解析生成的,浏覽器在js中提供了固定的 DOM API來操作 DOM 對象;特點/差別
-
:當元素發生更新時,記憶體中存在新舊兩個DOM樹對象,浏覽器通過新樹替換舊樹進行重新渲染頁面;工作原理
-
- 虛拟DOM
-
:手動使用JS對象來模拟(相對真正dom對象做了簡化)DOM樹,也是對象,然後通過特定方法渲染成真正的DOM,在頁面中出效果;本質
-
:彌補浏覽器不能新舊對比、實作指定更新的不足,為了實作DOM節點的高效更新;作用
-
:通過JS建立對象,模拟一個DOM節點,節點中有children屬性描述子節點,通過節點間嵌套,就模拟出了一個DOM樹;怎麼模拟DOM樹
-
:不是由浏覽器提供的,是開發人員自己通過JS模拟出來的,浏覽器解析的是js代碼,然後參照這個js代碼建立真正dom樹展示;特點/差別
-
:在頁面更新前,使用JS文法模拟出新舊兩個DOM樹,(因為浏覽器沒有提供擷取它記憶體中DOM樹的接口),然後使用
進行比較;讓浏覽器隻更新有變化的元素。diff算法
-
- 像vue、react架構中,頁面都是通過虛拟DOM轉為真正DOM來展示的;原理都類似;隻是感覺react更直白一些,vue更貼心一些,寫的時候還是可以寫html、css;
- react中建立頁面元素:與内部建立虛拟DOM做法類似,都是直接通過
實作,不再直接寫html标簽;與vue不同(通過html标簽寫頁面);js+接口
二、react中的Diff算法
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNCM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csIXNXllb1cVWvB3MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3MDOwQDO1kTM5ATOwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
前提
:有新舊兩個虛拟DOM了,通過把舊虛拟dom一步步修改變成新虛拟dom一樣的過程中,得到需要變化的元素;
意義
:diff 是通過JS層面的計算,對比新舊虛拟DOM,傳回一個patch對象,即更新檔對象,在通過特定的操作解析patch對象,完成頁面的重新渲染;
1、
tree diff
:将新舊兩個整體的虛拟DOM,逐層對比;其中包含元件對比、元素對比;
2、
componment diff
:(react中元件類似vue,就是首頁面引入的部分)在對比每一層時,進行元件之間對比;
- 元件對比規則:
- 相同位置,兩個元件類型相同,就暫且儲存先認為不用更新;如果類型都不同,那直接移除舊元件,建立元件替換到被移除的位置;(這些後會被記錄)
3、
element diff
:元件中元素之間的對比;
4、
key屬性
:把頁面中 DOM節點 與虛拟DOM中的對象,做一層關系。
三、react中的JSX文法
背景
:因為在react中書寫元素都是在js中,react原生提供了
react、react-dom
來支援;
import React from 'react'
/react子產品,用于專門來建立react元件、生命周期等;
import ReactDom from 'react-dom'
/react-dom子產品,用于将元件渲染到頁面上,内部封裝了和DOM相關的包;
var myDiv = React.createElement('div',{title:'mytitle',id:'myDiv'},'文本内容');
ReactDom.render(myDiv,document.getElementById('app'))
/=ReactDom.render(虛拟dom,嵌套元素)
不足
:原生方法書寫html元素,比較麻煩,開發人員更喜歡可以以手寫
html代碼
的方式定義頁面,是以react中提供了
JSX文法
來支援在 js 中書寫html标簽;
1、jsx介紹
-
:符合 XML 規範的 JS 文法,即手寫的html标簽要符合XML标準;定義
-
:内部将js中的html代碼用原生原理
轉換成React.createElement方法
,再交給js對象
渲染;ReactDOM.render()
-
:webpack一開始是不識别JSX文法的,需要安裝配置怎麼用
文法轉換工具(@babel/preset-react
babel-loader 7.x對應:babel-preset-react);注:
-
效果展示
var myDiv = <div id="myDiv">jsx識别的文法
<p id="mySpan">js中寫html沒有文法提示</p>
</div>
// =後面就是jsx文法,
//會被解析成render函數的傳回值:
//React.createElement('div',{title:'mytitle',id:'myDiv'},'文本内容')
ReactDom.render(myDiv,document.getElementById('app')) //傳入render函數,内部執行形成得到createElement()函數,這個函數執行生成虛拟dom,并渲染出真正dom
2、jsx文法解析規則:
-
:在基本規則
遇到js檔案中
就按html代碼解析,轉成js對象;遇到<>
或者正常的js代碼就按js代碼解析;{}
-
:在HTML代碼中有一些名稱與js關鍵字沖突,是以在使用時要改名;如:JSX中要寫變化
,文法内會解析成正常<div className="myClass"></div>
<div class = "meClass">
-
:單行、多行注釋JSX中html的注釋
{/* 這是p标簽 */}
<p id="mySpan">js中寫html沒有文法提示</p>
{
// 多行注釋
// 多行注釋
}
四、react中的元件
元件檔案
:元件檔案名字尾:
.jsx/.js
,差別在于
.jsx檔案
中有html文法提示;都需要然後在webpack中配置
babel文法轉換器
;
1、
function方式
定義元件
- 函數元件通過
形參,接收外界傳進來的資料,将props
,而且資料是隻讀的,不能内部修改;接收的資料以props對象的屬性方式存儲
- 外界通過在函數标簽中定義屬性的方式傳遞資料;
- 函數元件定義時必須大寫開頭,因為函數的元件使用方式就是以函數名為标簽名,而
中解析标簽是:小寫标簽按正常html标簽解析,大寫标簽才會當做元件标簽解析;jsx文法
元件:Hello.js
import React from 'react'
function Person(props){
return <div>
<h1>哈哈---{props.name+"--"+props.age}</h1>
</div>
}
export default Person
---
入口檔案:main.jsx
import Hello from './componments/Hello' /=>類似vue,引入Hello元件直接就是render函數,
/=>這是由檔案内部導出時解析結果決定的
var one = {
name:'zs',
age:12
}
ReactDom.render(<Person one={one}></Person>
,document.getElementById('app'))
//或者可以展開方式:{props.name+"---"+props.age}
ReactDom.render(<Person {...one}></Person>
,document.getElementById('app'))
2、
class方式
定義元件
- 類的執行個體是繼承構造函數中的屬性和方法;
- 類中構造函數外定義的普通方法挂載到原型對象上,類的執行個體可以通過原型鍊使用;
- 類中構造函數外定義的屬性(隻能定義靜态)、靜态方法是挂載到了構造器上,類的執行個體通路不到;
-
:對比class與function構造函數補充
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
console.log('函數原型上的方法');
}
Person.info = '構造函數自身的屬性';
Person.addInfo =function(){
console.log('構造函數自身的方法');
};
var p1 = new Person('zs',21)
console.log(p1);
----
class Per{
/類中隻能定義方法(執行個體方法、靜态方法)和靜态屬性
/類中方法定義到構造函數原型上,隻能調用原型或通過執行個體使用
/類中靜态屬性、靜态方法定義在構造函數自身,隻能自身或子類繼承後調用
constructor(name,age){//類中的構造函數(方法),new執行個體自動執行
this.name = name;
this.age = age;
}
say(){//方法
console.log('class中構造函數原型上的方法');
}
static info = '類中的靜态屬性';//靜态屬性
static add = function(){
console.log('靜态方法也定義構造函數自身');
}
}
-
:在class定義元件中主要用到補充
類的封裝、繼承特性
class Per{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log('定義在Per構造函數原型上的方法');
}
static info = 'zs';/構造函數中的屬性,隻能通過構造函數調用
}
class Chinese extends Per{
constructor(name,age,color){
super(name,age);/父類的傳參必須放在前面
this.color = color;
}
}
var p2 = new Chinese('yellow','zs',22)
console.log(Chinese.info);/子構造函數可以調用父構造函數中靜态屬性/方法,但是執行個體不行
- 需要繼承
;React.component
- 類中需要定義
render方法傳回null或jsx文法(讓内部解析成createElement()函數)
- 與函數元件類似,最終都是用名字做标簽名,内部最終傳回的都是:h();
-
,參數1:使用的就是ReactDom.render()
React.createElement()
main.js:
class Hello2 extends React.Component{ /=>繼承react元件功能
render(){
return <div>這是class類建立的元件{this.props.aa}</div>
} /=>定義render函數,内部傳回值會被JSX解析,是以最終return的結果就是:createElement()函數;
}
ReactDom.render(<div>
<Hello2 aa='asdClass'></Hello2> ://=這就相當于new了一個Hello2類的執行個體并執行了render函數,render是執行個體原型鍊上的方法
</div>,document.getElementById('app'))
3、對比兩種元件定義方式
- 差別一:參數props的使用
- 在function元件中,通過标簽接收參數,需要傳入
,通過props
的方式使用;{props.[屬性名]}
- 在class元件中,同樣标簽接收參數,不需要傳參數(也沒有地方接收),直接通過
使用;{this.props.[屬性名]}
- 在function元件中,通過标簽接收參數,需要傳入
- 差別二:兩者都不能對傳入參數做修改;
- 差別三:函數元件是無狀态的元件;class類定義元件是有狀态的;
- 有狀态:可以有自己的類似vue中data的屬性,即
;this.state={}
- 函數元件使用時就是執行構造函數傳回 h()虛拟dom
- class元件使用時也執行了new,同時也執行了render函數,狀态就可以在new時建立,在render函數執行時改變;
- 有狀态:可以有自己的類似vue中data的屬性,即
- 有無狀态差別:
- 有狀态元件:有私有資料(state屬性),有生命周期函數;适用于需要修改資料的元件;
- 無狀态元件:沒有私有資料,無state屬性,無生命周期函數;适用于資料不改變的元件,
;如子元件
4、元件中state/data與props差別
- 前者是元件私有的資料,通過ajax請求來的;
- 後者是外界傳過來的資料;
- 前者的資料是可讀可寫的;
- 後者的資料是隻讀的;
五、react中的class有狀态元件應用
1、路徑問題
path.join(__dirname,'./aa'); /='aa' '/aa' './aa' 效果一樣:e:\QD\react\aa
path.join(__dirname,'../aa'); /= 向上一級:e:\QD\aa
不識别'/'根目錄
path.resolve(__dirname,'./aa'); /='aa' './aa' 效果一樣:e:\QD\react\aa
path.resolve(__dirname,'../aa'); /= 向上一級:e:\QD\aa
path.resolve(__dirname,'/aa'); /= e:\aa
都是轉為絕對路徑;resolve識别/,為根目錄
下一個》》2、