js事件節流、防抖、事件委託

事件節流

事件節流和防抖是爲了解決開發過程中遇到性能問題,常見於onscroll、onresize,頻繁點擊button等

原理
設置一個時間間隔,時間間隔內只允許執行一次

例子
onresize問題,頁面滿屏佈局,模塊很多dom結構也相對複雜。所以在窗口頻繁快速變化大小的時候頁面反應異常卡頓。

// onresize 事件會在窗口或框架被調整大小時發生。
window.onresize = () => {
	console.log('resize')
}

窗口大小變化時,會觸發得很頻繁,導致性能問題,
解決性能問題,就得減少執行次數

let timer = null
window.onresize = () => {
      console.log(timer)
      if (!timer) {
          timer = setTimeout(() => {
              callBack()
              timer = null
          }, 2000)
      }
  }

  function callBack() {
      console.log('resize')
  }

不管窗口怎麼變,2s內只會執行一次

也可以直接用lodash庫的debounce方法
lodash中文文檔

事件防抖

常用於驗證碼防刷,按鈕頻繁點擊導致發起多次請求給服務端造成壓力
解決原理,重複觸發最後一次超過停頓時間時,才執行

實現:
input輸入內容停頓間隔2000ms後觸發callback


let oInput = document.querySelector('input')
// oInput.addEventListener('input', function(e) {
//     //如果直接每次onInput發請求,會導致性能問題
//     console.log(e, this)
// })

oInput.addEventListener('input', debounce(callback, 2000))

function debounce(fn, delay) {
let timer = null
    // 綁定上下文this
let self = this
return function() {
    let arg = arguments
        // 每次清楚定時器
    clearTimeout(timer)
        // 重新打開定時器,做到只有最後一次執行了
    timer = setTimeout(() => {
        // 綁定this,傳入參數給callback。通常我們需要事件對象就ok
        fn.apply(this, arg)
    }, delay)
}
}

function callback(e) {
console.log('觸發', e.target.value)
}

事件委託(事件代理)

事件代理(Event Delegation),又稱之爲事件委託。是JavaScript中常用綁定事件的常用技巧。顧名思義,“事件代理”即是把原本需要綁定在子元素的響應事件(click、keydown…)委託給父元素,讓父元素擔當事件監聽的職務
事件代理的原理是DOM元素的事件冒泡

事件冒泡

一個事件觸發後,會在子元素和父元素之間傳播(propagation)。這種傳播分成三個階段
在這裏插入圖片描述
如上圖所示,事件傳播分成三個階段:

  • 捕獲階段:從window對象傳導到目標節點(上層傳到底層)稱爲“捕獲階段”(capture phase),捕獲階段不會響應任何事件;
  • 目標階段:在目標節點上觸發,稱爲“目標階段”
  • 冒泡階段:從目標節點傳導回window對象(從底層傳回上層),稱爲“冒泡階段”(bubbling phase)。事件代理即是利用事件冒泡的機制把裏層所需要響應的事件綁定到外層;

事件委託的優點

  • 可以大量節省內存佔用,減少事件註冊,只在父元素ul綁定一次事件,不需要在每一個li上綁定事件
  • 當新增子對象時無需再次對其綁定(動態綁定事件
<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中間還有未知數個 li

如上面代碼所示,如果給每個li列表項都綁定一個函數,那對內存的消耗是非常大的,因此較好的解決辦法就是將li元素的點擊事件綁定到它的父元素ul身上,執行事件的時候再去匹配判斷目標元素。

代碼

  • JavaScript原生實現事件委託

比如我們有這樣的一個 HTML 片段,點擊li標籤時要觸發事件

<ul id="myLinks">
  <li id="goSomewhere">Go somewhere</li>
  <li id="doSomething">Do something</li>
  <li id="sayHi">Say hi</li>
</ul>

不通過事件委託的方式,代碼如下


    var item1 = document.getElementById("goSomewhere");
    var item2 = document.getElementById("doSomething");
    var item3 = document.getElementById("sayHi");
 
    item1.onclick = function() {
      location.href = "http://www.baidu.com";
    };
    item2.onclick = function() {
      document.title = "事件委託";
    };
    item3.onclick = function() {
      alert("hi");
     }

在一個複雜的 Web 應用程序中,對所有可單擊的元素都採用這種方式,那麼結果就會有數不 清的代碼用於添加事件處理程序。
此時,可以利用事件委託技術解決這個問題。使用事件委託,只需在 DOM 樹中儘量最高的層次上添加一個事件處理程序,如下面的例子所示


    var item1 = document.getElementById("goSomewhere");
    var item2 = document.getElementById("doSomething");
    var item3 = document.getElementById("sayHi");
 
    document.addEventListener("click", function (event) {
      var target = event.target;
      switch (target.id) {
        case "doSomething":
          document.title = "事件委託";
          break;
        case "goSomewhere":
          location.href = "http://www.baidu.com";
          break;
        case "sayHi": alert("hi");
          break;
      }
  • vue中事件對象
    @click="show($event)

通過$event獲取事件對象

<el-input
   v-model="search"
   placeholder="搜索商家或地點"
   @focus="focus($event)"
   @blur="blur"
   @input="input"/>

兼容性寫法

//獲得event對象兼容性寫法 
event || (event = window.event);

//獲得target兼容型寫法 
event.target||event.srcElement

//阻止瀏覽器默認行爲兼容性寫法 
event.preventDefault ? event.preventDefault() : (event.returnValue = false);

//阻止冒泡寫法 
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true);

JS冒泡、捕獲、默認事件那些事


謝謝你閱讀到了最後
期待你,點贊、評論、交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章