[英]How to remove event listener of an element when I remove the corresponding element in the midst of the event being triggered in D3?
當我在D3中觸發的事件中刪除相應的元素時,如何刪除元素的事件偵聽器?
現在,在我調用.remove()
,似乎該事件仍在持續。
例如,我有一個事件偵聽器,該事件偵聽器監聽mousedown,如果我一直鼠標按下並使用鍵盤刪除相應的元素,mousedown事件仍然會持續。 這是預期的嗎?
更具體地說,我正在處理元素調用的d3.drag()函數。
如果是這樣,是否有一種方法可以一次清除所有它們,還是需要手動將其刪除? 如何清除揮之不去的事件?
以下是復制鏈接: https : //jsfiddle.net/38wtj4y0/33/
嘗試拖動矩形, 不要松開鼠標 。 按下一個鍵,該矩形將消失,但是當您在四處移動鼠標(仍然按下鼠標)時,您將看到控制台仍在打印“拖動”
更新
@Gerardo Furtado在下面的回答仍然是一種變通辦法,即使用if語句使所有觸發的函數返回。 換句話說,如果用戶在場景后不松開鼠標,則該拖動功能將永遠被觸發,只是他們將不做任何事情,因為它們將返回。 這仍然是完全的資源浪費。
我能想到的唯一導致此問題的解釋是,D3僅在不再處於活動狀態時才可以刪除事件偵聽器,即它必須等待用戶釋放。 因此,我需要一種釋放所有觸發的用戶交互的方法。
盡管我必須承認,這是一個有趣的問題,但我從未在現實世界的應用程序中遇到過此問題。 發生這種情況的原因可以在D3的拖動實現的內部工作中找到。
首先,值得一提的是,如果從DOM樹中刪除一個元素,則在對指針事件進行命中測試時,該元素將不再成為目標。 因此,將不再執行在該元素上注冊的事件偵聽器。 這是人們期望的行為,這也是您感到困惑的原因,因為在JSFiddle中,即使成功刪除了元素,偵聽器似乎仍在執行。
要了解發生了什么,您必須深入研究d3.drag()
的源代碼 。 初始化時,拖動行為會在選擇的元素上注冊各種事件處理程序:
function drag(selection) {
selection
.on("mousedown.drag", mousedowned)
//...
}
偵聽mousedown
事件的處理程序不會在相應元素上觸發此類事件之前設置其余的拖動行為。 一旦拖動行為的元素收到mousedown
事件,便將執行內部mousedowned()
處理程序:
function mousedowned() {
//...
select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
//...
}
在此處理程序的"mousemove.drag"
和"mouseup.drag"
聽眾注冊上event.view
。 MouseEvent
此view
屬性從UIEvent
接口繼承,並且(至少在瀏覽器中)指向事件發生在其中的Window
對象UIEvent
-drag使用全局window
上的那些拖動處理程序來完成其工作。 這些處理程序應對您目睹的令人困惑的行為負責。 我們將很快解決這個問題,首先讓我們檢查一下隨后如何刪除監聽器。
當拖動手勢最終通過觸發mouseup
事件結束時,這些處理程序將從函數mouseupped()
的window
對象中移除:
function mouseupped() {
select(event.view).on("mousemove.drag mouseup.drag", null);
}
現在,讓我們再來看一下您的代碼。 即使您刪除了由keydown
事件觸發的拖動行為的目標, window
上的上述處理程序仍然存在,因為您按住了鼠標按鈕可以抑制觸發mouseup
事件。 因此, mouseupped()
處理程序尚未執行。 由於mousemove
事件仍由window
上的拖動的內部處理程序捕獲,因此這將使拖動行為保持活動狀態。 此外,這些內部處理程序還將繼續委派給您自己的dragged
處理程序,從而導致您看到控制台輸出。
如本文開頭提到的那樣,我從未見過這會引起任何現實世界的麻煩。 盡管如此,如果您想避免這種行為,則可以在刪除目標后刪除內部處理程序:
d3.select(window).on("keydown", function() {
d3.select(".draggable-rect").remove();
d3.select(d3.event.view) // Remove global (internal) drag handlers
.on("mousemove.drag", null)
.on("mouseup.drag", null);
})
與擺弄某些庫的內部工作一樣,您必須保持謹慎,不要破壞其他內容,並要記住,這可能會在將來發布的任何D3版本中無聲地破壞。
看看這個工作演示:
d3.select("svg").append('rect').attr('class', 'draggable-rect'); d3.select(window).on("keydown", function() { d3.select(".draggable-rect").remove(); d3.select(d3.event.view) .on("mousemove.drag", null) .on("mouseup.drag", null); }) d3.select(".draggable-rect") .call(d3.drag().on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); function dragstarted(d) { d3.select(this).raise().classed("active", true); } function dragged(d) { console.log("dragging") d3.select(this).attr("x", d3.event.x - 40).attr("y", d3.event.y - 40); } function dragended(d) { d3.select(this).classed("active", false); }
.test-area { width: 400px; height: 400px; border: 1px solid black; } svg { width: 400px; height: 400px; } .draggable-rect { width: 80px; height: 80px; fill: green; }
<script src="https://d3js.org/d3.v4.js"></script> <div class="test-area"> <svg> </svg> </div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.