背景
如今的前端圈堪比是娛樂圈,雖然火熱程度不及當年,但是活躍程度還是很厲害的,各種技術令人眼花繚亂。從小程式到各種混合開發的解決方案,從vue,react到angular,從canvas到three.js甚至webgl,從cmd到nodejs,從gulp到webpack,各種技術讓人眼花繚亂,感覺學不過來了有沒有。其實這些技術我們只要朝著一個方向努力慢慢積累,總結就會慢慢成長的,無需跳過心急。
看法
自己平時總是把精力放在node,webpack之類的東西上,但是很多東西都需要查,其實後來才發現基礎才是最重要的。我一直很看重基礎的學習,雖然我js基礎我很是不滿意,哈哈,但是我會像大家一樣一起學習,總結的,大家一起加油。最近在聽 喜馬拉雅app裡面的 《陪你讀書javacript》,不知道有沒有一起,如果剛好有喜馬拉雅,我推薦大家聽一下,直接搜就行,老師比較系統的講js,三個特別來形容吧,特別基礎
,特別深奧
,特備有趣
注:我不是打廣告的啊,我真的是聽了他的課,來總結的只是點的,哈哈
;
事件流
- 冒泡
- 捕獲
事件級別
- dom0 HTML
- dom2 屬性事件
- dom3 事件監聽
dom0事件(html事件)
<div onclick="alert('1')"></div>
複製程式碼
dom2事件(屬性事件)
let dom = document.querySelector(".dom");
dom.onclick = function(){
//執行程式碼
}
複製程式碼
dom3事件(事件監聽)
let dom = document.querySelector(".dom");
dom.addEventListener('click', function(){
// 處理函式
}, true);
複製程式碼
addEventListender接受三個引數,第一個引數為 事件名稱,如(click、mousedown),第二個為 事件對應的處理函式,第三個是 是否為事件捕獲常用的是傳一個 Boolean值(true表示在事件捕獲階段觸發,false表示在事件冒泡階段觸發),也可以傳一個物件,下面會詳細講解。
其實這些東西,js稍微有點基礎的同學們,都應該經常用這些東西,我總結一下方便大家記得更深刻,哈哈。下面主要講一下 addEventListener的幾個引數。
先給一下基礎的html結構
:
<div class="box">
<div class="child"></div>
</div>
複製程式碼
下面是javascript
程式碼:
let dom = document.querySelector(".dom");
dom.addEventListener('click', function(){
// 處理函式
}, true);
let box = document.querySelector('.box');
let child = document.querySelector('.child');
let boxEvent = function(){
console.log('box');
}
let childEvent = function(){
console.log('child');
}
box.addEventListener('click', boxEvent, true);
child.addEventListener('click', childEvent, true);
複製程式碼
這大家肯定都很瞭解,我就簡單總結一下:
程式碼如上,我們點選了child。
- 如果第三個引數為false(事件在冒泡階段觸發),那麼控制檯列印的順序為child,box
- 如果第三個引數為true(事件在捕獲階段觸發),那麼控制檯列印的順序為box,child
- 注意:不管css怎麼設定都不會影響事件的執行,比如 child通過css定位特別大,完全蓋住了這個box,依然不會影響事件執行書序。
如果我們要取消事件監聽把上面的
addEventListener
替換為removeEventListener
即可,但是需要注意以下幾點
- 如果事件的處理函式用的不是函式名,而是匿名函式,則無論如何都無法取消這個事件,因為我們無法找這個函式的引用。
- 事件的引數要對應,比如監聽的是捕獲時的事件(第三個引數為true)時,我們取消時也需要設定同樣的值,反之亦然。
上面提到
addEventListener
第三個引數也可以是個物件,我們平時一般很少會用到(至少我是很少用),下面就給大家仔細介紹下以便一起記憶,看下面的程式碼:
el.addEventListener(eventType, optionFunction, {
capture: false, // 和直接把第三個引數填寫布林值一樣,代表是否為捕獲時觸發事件
once: false, // 預設fasle,是否只執行一次
passive: false //預設為false,代表是否承諾瀏覽器不會呼叫e.preventDefault()來阻止預設行為
})
複製程式碼
對於
addEventListener
第三個引數裡的passive,在多講幾句吧,如下:
- 背景:對於一個事件監聽,瀏覽器是不知道他會不會執行預設行為(比如滾動條等),所以瀏覽器只能等事件結束了才會執行預設行為,而很多情況下,我們是不會禁止行為的,但是沒辦法,我們沒有給瀏覽器承諾,所以瀏覽器每次都需要等你執行完事件函式的東西才能知道你沒有呼叫e.preventDefault(),然後才執行預設行為,這就造成了資源郎芬
- 優點:對於一些我們不會阻止預設行為的情況,我們在監聽函式的時候,設定了passive:true,瀏覽器就會提前知道你並不會使用e.preventDefault(),瀏覽器就會自己進行優化無需等事件處理函式執行完就可以執行預設行為,這樣在有些極端情況下(比如處理特別頻繁的事件中比如,touchmove,scroll)會提高很多的效能
- 表現: 如果設定了passive:true,但是我們又設定了e.preventDefault()呢,親測chrome瀏覽器下會報錯,
Unable to preventDefault inside passive event listener invocation.
關於event
event.target
和event.currentTarg
區別
- event.target: 返回觸發事件的元素(在事件委託中用的就是target)
- event.currentTarget: 返回繫結事件的元素
下面是我自己實現小型jq中的
on
方法( dom繫結事件)
一般情況下
on(evtName, evtFunc, isCatch = true) {
document.addEventListener(evtName, (e) => {
this.domList.forEach(dom => {
if (e.target == dom) {
evtFunc.call(e.target);
}
})
}, isCatch);
}
$(".lala").on('click',function(){
console.log(this);// 列印當前觸發事件的元素
})
複製程式碼
如果上面的evtFunc.call(e.target);
為 evtFunc.call(e.currentTarget);
on(evtName, evtFunc, isCatch = true) {
document.addEventListener(evtName, (e) => {
this.domList.forEach(dom => {
if (e.target == dom) {
evtFunc.call(e.currentTarget);
}
})
}, isCatch);
}
$(".lala").on('click',function(){
console.log(this);// 這裡不管點選誰都列印 document了,因為是document繫結的事件
})
複製程式碼
總結
以上是我對js事件的一些總結,所有的程式碼都算是我直接在有道雲敲的,沒有用ide,入股哪裡有寫錯的,還請大家給以友善的提醒,或者有些的不合適甚至錯的地方,大家一起來糾正學習。
寫這些只是一個開始,我一會會定期更新基礎知識點的,希望大家一起來總結學習,有沒有發現很多知識,廢了好久的勁兒學會了,但是長久不用又忘了,這就需要我們學習的時候 即使總結下來,我們才會記得久一點。 如果想和我一起學習的,歡迎加我的學習群前端雜貨鋪(小遊戲/Vue)啦啦啦,群聊號碼:677482875,大家一起交流,嘻嘻噠。
from:愛你的蝸牛。