引言
無論新手老手,在前端開發中,經常要為DOM元素繫結事件,以實現某些功能。
如何通過一些JS技巧,達到減少事件繫結,優化頁面效能的目的呢?
接下來介紹一下我個人對優化事件繫結的實踐。
我儘量寫得通俗易懂一些,希望能為剛入門前端的人們帶來幫助。
也歡迎大家踴躍評論和指正,一起分享建議和想法哦。
事件繫結利器:利用事件冒泡機制
哈哈,放心,我不會強行地科普一堆瀏覽器事件機制晦澀的理論,
事件傳播機制在各種瀏覽器或版本上可能會有差異,在差異中尋找平衡點,冒泡機制是個突破口。
這裡直接給出最佳實踐:利用事件冒泡機制來為DOM元素繫結事件。
-
理由一:早期IE只有冒泡機制,統一使用冒泡機制來繫結事件,就解決了最棘手的IE瀏覽器相容性問題了。
-
理由二:事件傳播的冒泡階段,最接近頁面UI上看到的實際情況,由子元素逐級向父元素傳播,更加直觀並且容易理解。
-
理由三:對於動態新增的DOM元素,要直接為其繫結事件,只能推到元素建立後進行。但如果利用事件冒泡機制,不需要再為這個時間點所糾結。
例項
話不多說,直接上例項(下面的示例都不造輪子,直接用jquery了哈)。
假如現在有一個無序列表,需要在點選具體列表項時,於控制檯列印該項的HTML內容。
思路是:想辦法為DOM元素繫結事件 -> 獲取元素HTML -> 輸出到控制檯。
<ul class="list">
<li class="list-item">1</li>
<li class="list-item">2</li>
...
</ul>
差勁的事件繫結:使用老掉牙的onclick屬性
<ul class="list">
<li class="list-item" onclick="handler(this)"></li>
<li class="list-item" onclick="handler(this)"></li>
...
</ul>
function handler(e) {
console.log($(e).html());
}
一不留神懶惰先生跑了出來:OK搞定,完成任務!就這樣吧,能實現功能就可以了。
思考:
這是種最古老的事件繫結方式,沒有做到JS和HTML的分離,非常不利於維護,是隨著潮流要被淘汰的糟糕做法。
可是不禁感嘆,如今還是會在某些中小型網站、教材、還有大學課堂上看到它們的身影。然後新手們紛紛模仿,從起點開始就走了不少彎路,我也是過來人(捂臉)。
不錯的事件繫結:獲取元素集合並繫結事件
$(`.list-item`).on(`click`, function() { // 獲取元素集合並繫結事件
console.log($(this).html());
};
這次做到了JS和HTML的分離,先獲取元素集合,再利用jquery
的事件繫結方法on()
,解決瀏覽器事件API的差異問題。
思考:
如果有100個列表項的話,jquery
就會遍歷100次,為匹配的元素集合都繫結一個click
事件。
光這100次遍歷和繫結操作,就是件非常消耗資源的事情。
再加上由於建立太多的事件監聽,也會對頁面效能有影響。
更好的事件繫結:利用冒泡機制監聽父元素
$(`.list`).on(`click`, `li`, function(event) { // 繫結事件到父節點
console.log($(event.target).html()); // 注意操作物件是event.target還是this,下面會有詳細說明哦
});
優化後,將監聽函式放到了父元素上,通過只監聽父元素的一個事件,掌控了千千萬萬的列表項。
藉助冒泡機制,事件繫結由100優化到1,就是這麼愉快,哈哈哈。
注意點&細節解析:
使用on()
方法的篩選器
這裡用到了on()
方法的第二個引數,這個引數是個篩選器,例如li
,>li
,.list-item
,li.list-item
等。
當檢測到點選事件是由這個篩選器匹配的元素傳來的,就觸發這個父節點的click事件回撥函式。
篩選器沒有用.list-item
而是li
因為如果把css類作為篩選器的話,jquery
在執行時要把每個event.target
的class
屬性去查一查,然後拆分後看看是不是有叫list-item
。判斷步奏多了很多。
本示例中,只使用li
來篩選就已經滿足我們的需求了,優化要從細節開始哦。
注意回撥函式中操作的是this
還是event.target
因為當前是在父元素中繫結的事件,所以this
預設指向的是父元素,並不是我們的列表項。
但是這裡要強調一點:如果使用on()
方法中的篩選器自動篩選的話,jquery
也會自動幫我們把this
指向改成event.target
,這時候this
和event.target
都同樣指向的是列表項了,兩個都可以用哦。
建議使用event.target
,避免混淆,也可以讓程式碼更加清晰啦。
如果不使用jquery
在on()
方法中提供的篩選器的話,也可以自己去判斷冒泡過來的是不是li:
$(`.list`).on(`click`, function(event) {
if (event.target.tagName === `LI`) { // 判斷標籤是不是li,注意tagName屬性返回的是大寫
console.log($(event.target).html());
}
});
這樣子無論是用on()
方法的自動篩選,還是直接自己寫程式碼判斷,都可以統一使用event.target
來獲取冒泡階段傳播到此的具體列表項,我們就可以開心的去操作它啦。
結語:一切重在不滿足於現狀的精神
這裡介紹的只是幾個小點,在前端開發中能優化的地方還有很多很多。
重要的是精神層面上的東西,必須不滿足於現狀、多思考、多注重細節,才能逼著自己一點點向前爬過去。
謝謝你看到了最後,大家一起加油!