簡體   English   中英

如何改變DOM事件對象

[英]How to mutate a DOM event object

我處在一種情況,我必須寫自己的事件冒泡。 因此,我需要將給定的Event-Object (最初從Browser / DOM創建)傳遞給多個函數/實例,但我需要更改.target屬性。

問題 :幾乎所有屬性的屬性描述符都否定任何突變,刪除或更改。 此外,似乎無法使用Object.assign克隆或復制整個Event-Object,或使用Object.getOwnPropertyNamesObject.keys讀取屬性。

當然可以通過分配它們來手動將所有屬性復制到新對象中,但這看起來非常愚蠢。

我試圖變得非常聰明,只使用原始事件對象作為新對象的原型,只是遮蔽我想要變異的屬性。 喜歡

Object.setPrototypeOf( customEvent, event );

但是,如果我這樣做,任何對customEvent屬性的訪問都會拋出:

Uncaught TypeError: Illegal invocation

如果我們使用也可用於遮蔽某些屬性的代理處理程序 ,它似乎確實有效。 我在這里stopPropagation的唯一問題是,仍然無法通過代理執行stopPropagation函數( Uncaught TypeError:非法再次調用 )。

問題 :操作/擴展DOM事件對象的最佳實踐是什么?


如果你提到任何形式或形狀的jQuery,你將遭受7年的不幸。

我已經使用Proxy來解決這個問題,並結合了包裝器。

首先,設置一個充當代理的包裝器的函數。 包裝器接收一個Event對象並設置其值以供以后使用。 其原因將進一步解釋。

function AdaptedEvent(ev) {
  const initialEvent = ev;
  let newTarget = 'your new target'; // can be dynamic if you wish.

  // returning with a handler for proxy
  return {
    get: (target, prop) => {
      // proxy'ing stuff
    }
  };
}

然后在代理內部,我有

get: (target, prop) => {
  if (prop === 'target') {
    return newTarget ? newTarget : initialEvent.target;
  }
  return target[prop];
}

當你的代理對象調用.target時,它將執行上面if-body中描述的語句。 它將返回一個新目標而不是事件的初始目標。

設置代理后,必須在處理單擊事件時構造代理對象。 喜歡

document.querySelector('#foo').addEventListener(
  'click',
  e => handleClick(new Proxy(e, new AdaptedEvent(e)))
);

例:

 function AdaptedEvent(ev) { const initialEvent = ev; let newTarget = 'your new target'; return { get: (target, prop) => { if (prop === 'target') { return newTarget ? newTarget : initialEvent.target; } return target[prop]; } }; } function handleClick(event) { console.log(event.target); console.log(event.which); } // binding click event. document.querySelector('#foo').addEventListener('click', e => handleClick(new Proxy(e, new AdaptedEvent(e)))); 
 <button id="foo">click me!</button> 

但正如你提到的那樣,我在嘗試時也看到了一個問題:

如果我們使用也可用於遮蔽某些屬性的代理處理程序,它似乎確實有效。 我在這里stopPropagation的唯一問題是,仍然無法通過代理執行stopPropagation函數( Uncaught TypeError:非法再次調用 )。

在下面的例子中; 我已將按鈕替換為鏈接。 假設我想通過使用.preventDefault()來阻止它冒泡。 你可以看到它會引發上面提到的錯誤。

 function AptEvent(ev) { const initialEvent = ev; let newTarget = 'your new target'; return { get: (target, prop) => { if (prop === 'target') { return newTarget ? newTarget : initialEvent.target; } return target[prop]; } }; } function handleClick(event) { event.preventDefault(); console.log(event.target); console.log(event.which); } // binding click event. document.querySelector('#foo').addEventListener('click', e => handleClick(new Proxy(e, new AptEvent(e)))); 
 <a id="foo" href="www.google.com">click me!</a> 

這樣做的原因是,在調用所述函數時,您已經失去了調用preventDefault的正確上下文。 對此的解決方案是使用.bind 但是你應該把什么傳遞給.bind 是的,本機Event對象。 這就是為什么我設置了上面的AdaptedEvent函數,它接收一個Event對象作為參數。 現在,您可以在對屬性的調用是函數時輕松傳遞該對象(輕松檢查)。

單擊鏈接時,事件冒泡停止。

 function AdaptedEvent(ev) { const initialEvent = ev; let newTarget = 'your new target'; return { get: (target, prop) => { if (Object.prototype.toString.call(target[prop]) === '[object Function]') { return target[prop].bind(initialEvent); } else if (prop === 'target') { return newTarget ? newTarget : initialEvent.target; } return target[prop]; } }; } function handleClick(event) { event.preventDefault(); console.log(event.target); console.log(event.which); } // binding click event. document.querySelector('#foo').addEventListener('click', e => handleClick(new Proxy(e, new AdaptedEvent(e)))); 
 <a id="foo" href="www.google.com">click me!</a> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM