不要問自己需要什麼樣的人生,而要問自己想要成為什麼樣的人。 我們從前面的學習知道一個 React 組件不僅僅只包含 DOM 結構的,還應該樣式和 Javascript 邏輯的。這裡我們認識邏輯構造之事件處理。 1. React 事件處理 這裡列舉了在 React 中事件的幾種綁定處理方式: impo ...
不要問自己需要什麼樣的人生,而要問自己想要成為什麼樣的人。
我們從前面的學習知道一個 React 組件不僅僅只包含 DOM 結構的,還應該樣式和 Javascript 邏輯的。這裡我們認識邏輯構造之事件處理。
1. React 事件處理
這裡列舉了在 React 中事件的幾種綁定處理方式:
import React, { Component } from "react";
class App extends Component {
render () {
return (
<div>
<input/>
<button onClick={ ()=>{ console.log("第一種事件綁定處理方式") }}>Add-1</button>
<button onClick={ this.handleClick2 }>Add-2</button>
<button onClick={ this.handleClick3 }>Add-3</button>
<button onClick={ ()=>{ this.handleClick4() } }>Add-4</button>
</div>
)
}
handleClick2() {
console.log("第二種事件綁定處理方式")
}
handleClick3 = ()=>{
console.log("第三種事件綁定處理方式")
}
handleClick4 = ()=>{
console.log("第四種事件綁定處理方式")
}
}
export default App;
2. 事件綁定區別
這裡重點說明下在事件和事件綁定綁定中 this 指向問題。
2.1 匿名函數
直接執行匿名函數,直接在 {} 中寫事件函數表達式。
寫法特點:
- 適合邏輯少、簡單表達式。如果處理邏輯過多、複雜 ,會導致結構不清晰,難維護,不推薦。
- 事件內部 this 指向和外部一致,因為箭頭函數沒有 this 指向問題原則。
能直接訪問:
- 因為 onClick 後面表達式跟的是一個函數(箭頭函數),這裡事件內部 this 指向和外部一致。
class App extends Component {
// 定義屬性
value = 100
render () {
return (
<div>
<input/>
<button onClick={ ()=>{ console.log("第一種事件綁定處理方式", this.value) }}>Add-1</button>
</div>
)
}
2.2 調用內部普通函數
寫法特點:this 指向和外部不一致,需要用 bind 修正 this 指向,不推薦使用。
<button onClick={ this.handleClick2 }>Add-2</button>
// 修正後:
<button onClick={ this.handleClick2.bind(this) }>Add-2</button>
handleClick2() {
// 異常,需要通過改變 this 指向解決
console.log("第二種事件綁定處理方式", this.value)
}
不能直接訪問:
這裡訪問類屬性 this.value 會報錯,我們可以列印出 this 看下它指向什麼,結果會是:undefined。為什麼 this 會丟失呢?記住一句話:函數中的 this 誰調用我,this 就指向誰。這裡點完按鈕後被 React 事件系統調用的,this 指向的應該是 React 事件系統。用於不會指向 App 這個實例。而這裡它也沒有指向 React 事件系統,而是丟了指向 undefined。哈哈哈....
2.3 調用內部箭頭函數
寫法特點:this 指向和外部一直,沒有 this 指向問題,推薦使用。
<button onClick={ this.handleClick3 }>Add-3</button>
handleClick3 = ()=>{
console.log("第三種事件綁定處理方式", this.value)
}
這裡是箭頭函數,this 指向根本不關心誰調用的我,它永遠保持與外部作用域一樣的,它指向的 app 的實例。為什麼箭頭函數 this 指向就不關心誰調用的我呢?我也不知道.... 難到....
- 箭頭函數會自動改變 this 的指向???
- 或者箭頭函數不是改變 this 指向,而是引用上一個作用域的 this ???
- 一個比較權威的解釋是在箭頭函數中,this 與封閉詞法上下文的 this 保持一致。在全局代碼中,它將被設置為全局對象。
2.4 執行匿名函數,調用其他內部函數
寫法特點:this 指向和外部一直,沒有 this 指向問題,符合誰調用我我指向誰。非常推薦使用這種寫法,參數傳遞很方便。
<button onClick={ ()=>{ this.handleClick4() } }>Add-4</button>
// 語法簡寫:
<button onClick={ ()=>this.handleClick4() }>Add-4</button>
// 有人說這裡是因為你寫成了箭頭函數了吧,即使他不寫成箭頭函數也沒關係,剛纔講的原理,符合誰調用我我指向誰。
handleClick4 = ()=>{
console.log("第四種事件綁定處理方式", this.value)
}
整體有個問題: 要不要加小括弧,不加不讓他自己主動執行,點擊系統會調用、加小括弧執行函數。加小闊號主動執行,點擊後不執行 undefined。
2.5 JS 中修正 this 指向方案
- call:改變 this 指向,自動執行函數;
- apply:改變 this 指向,自動執行函數;
- bind:改變 this 指向,不會自動執行函數,需要手動加括弧執行函數 ;
var obj1 = {
name: "obj1",
getName() {
console.log(this.name)
}
}
var obj2 = {
name: "obj2",
getName() {
console.log(this.name)
}
}
// this.name 誰調用我我指向誰
obj1.getName() // 結果 obj1
obj2.getName() // 結果 obj2
// call, reply :修改 obj1 getName 中 this 指向 obj2
obj1.getName.call(obj2) // 結果 obj2
obj2.getName() // 結果 obj2
3. 總結事件處理
3.1 this 指向問題,記住兩句話
- 誰調用我我指向誰原則;
- 箭頭函數沒有 this 指向問題;
3.2 React 事件綁定和原生事件綁定有什麼區別?
React 中事件綁定沒有綁定到具體的 DOM 節點(元素)身上。它採用的是一種事件代理的模式,綁定在根節點身上。綁定到每一個 DOM 節點身上是很消耗記憶體的。
React 模擬了一套事件冒泡機制,等冒泡到根節點上通過 target 事件源找到是那個元素真實觸發的,然後從這個觸發的元素到頂點所有節點都去查一查,有沒有一個叫 onClick 屬性,如果有就把這個 onClick 事件給執行了,完整模擬冒泡的流程,即模擬系統事件機制。其不需要考慮解綁、移除事件等,只有節點從頁面中沒了,onClick 根本就不會再有了,沒有綁定只有節點沒了 onClick 就沒了。
3.3 Event 事件對象也是支持的
Event 對象,和普通瀏覽器一樣,事件 handler 會被自動傳入一個 event 對象,這個對象和普通的瀏覽器 event 對象所包含的方法和屬性都基本一致。不同的是 React 中的 event 對象並不是瀏覽器提供的,而是它自己內部所構建的。它同樣具有 event . stoppropagation、event.preventDefault 這種常用的方法。