删除触发事件监听器的事件监听器。

3
注意:有很多与删除事件监听器相关的问题。在简单情况下,可以将匿名JS函数移动到具有指定名称的命名函数中,然后使用removeEventListener调用该函数来解决问题。
例如:
element.addEventListener("click", function(event){console.log("you clicked me");)})

去到
function youClickedMe(event) {console.log("you clicked me");}
element.addEventListener("click", youClickedMe)

然后在其他地方

element.removeEventListener("click", youClickedMe)

在我的情况下,这要复杂一些。

  1. 我有一个需要传递的封闭变量
  2. 我的事件绑定了新的事件监听器

当 DOM 进入特定模式(按下按钮,切换布尔值)后,我试图捕获用户单击左键鼠标(LMB)并将鼠标移动到某个特定区域时的操作。

到目前为止,它的效果还不错,请参见 fiddle

但是,无论我尝试什么, "mousemove" 事件都无法消失。

此外,当我将 d3.zoom / d3.pan 函数添加到混合中时,情况变得更糟... 但那是另一个问题。

如何删除这个/这些添加的事件?你们有什么想法吗?


2
问题在于,当您取消绑定事件侦听器时,您不再具有对其绑定的函数的引用。 (因为每次调用处理程序时,您都会创建一个新的mousedown函数)。 为什么不只是拥有一个全局变量,告诉您状态(即切换是否打开,并且可能是颜色数组的索引)? - jake2389
@jake2389 如果我将 mouseDownAndMove 移到函数外面,那么它可能会起作用吗?好问题。该内容具有动态创建和删除的功能,因此可能会有多个实例都作用于同一个 SVG... 在创建它们的闭包中,我有一个全局切换变量,但这对需要一些本地变量的函数没有帮助... - SumNeuron
我实际上是在谈论第38行的mousedown函数,但对于mouseDownAndMove也是如此。如果您正在动态创建和销毁它们,则闭包可能不是最好的选择,因为使用它们可能会导致一些严重的内存泄漏 - jake2389
@jake2389 说得好。我会尝试重新组织结构。 - SumNeuron
2个回答

3

评论中已经解释过的那样,您在这里引用了不同的函数。

如果由于某种原因您无法重构代码和逻辑,则可以将null作为D3选择器的监听器传递:

svg.on('mousedown', null)

顺便说一下,在D3的代码中,使用D3方法比使用纯JS方法更加方便。

以下是已经进行了修改的代码:

// toggle events with button
d3.select("button").on("click", toggle)
// for convenience
var svg = d3.select("svg")
// some external vars, could be closure vars...
var counter = 0;
var colors = ["red", "coral", "black", "white"]


function toggle(d, i) {

  var btn = d3.select(this)
  var activeQ = btn.classed("active")
  // toggle
  activeQ = !activeQ
  btn.classed("active", activeQ)

  // I have something like this in my code, and could be 
  // the route of the bug... but here for completeness
  var closedVar = "I can only be (easily) calculated here, but am needed in the event";

  if (activeQ) {
    // new toggle, start counter over
    counter = 0
    svg.on('mousedown', mousedown)
  } else {
    // remove the mouse down event
    svg.on('mousedown', null)
    // could clean up svg here, but for demo purposes leave it

    // maybe custom event to cleanup elsewhere?
    /* svg.dispatch("cleanup") */
  }

  // this function can use the local var closedVar
  // and be named in addEventListener
  function mousedown(event) {
    dropPoints(event, closedVar)
  }

}


function dropPoints(event, closedVar) {
  // want to only trigger on mouse down and move
  var pts = []
  svg.on('mousemove', mouseDownAndMove)
  svg.on('mouseup', function(event) {
    counter += 1;
    svg.on('mousemove', null)
  })


  /* svg.node().addEventListener('cleanup', function(event) {
    svg.node().removeEventListener('mousemove', mouseDownAndMove, true)
  }) */

  function mouseDownAndMove() {
    // event.which === 1 for mouse events ~might~ be left mouse button... at least in jQuery
    if (d3.event.which != 1) {
      return
    }

    var pt = d3.mouse(svg.node())

    svg.append("circle").attr("r", 3).attr("fill", colors[counter % (colors.length)])
      .attr("cx", pt[0])
      .attr("cy", pt[1])


  }
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
  svg {
    width: 300px;
    height: 200px;
    background-color: blue;
  }
  
  .active {
    background-color: coral;
  }
</style>

<button>
Click to activate
</button>

<svg id="demo" width="500" height="500" style="background-color:blue;">
  
</svg>


我已经重构了代码。虽然它还不是最终形式,但你可以在这里测试我制作的东西:https://sumneuron.gitlab.io/d3sm/demos/scatter/index.html 我认为你可能会喜欢它。+1 个工作解决方案(尽管我已经修复了自己的代码)。尽管我很喜欢 d3,但我认为原生 JS 事件处理程序可能更好?我在 d3 中绑定事件时遇到了问题,而在原生 js 中则没有...虽然这可能只是我对 d3.on 和相关函数缺乏经验。 - SumNeuron
D3是一个JS库,因此任何原生JS都可以在D3代码中使用。但大多数情况下,这并不是最方便或最惯用的方式。 - Gerardo Furtado

1

https://jsfiddle.net/jgv37zzk/

我尝试移动一些东西。一个关键的问题是removeEventsListener没有起作用,因为你将useCapture标志设置为true,但在addEventListener中未设置它。 我不完全确定您想要使用dropPoints函数做什么(因为目前它只是绑定事件侦听器),但如果提供更多上下文,我可能会更新答案。

+1,因为您指引了我正确的方向来回答我的问题;然而,链接的fiddle遇到了与我的原始fiddle相同的问题。dropPoints函数在那里,因为这是我的代码(而不是MWE)遇到这个bug的方式。所以我不确定是不是这个函数有问题。但是在重构后,它就像魅力一样工作了 :) 非常感谢您。 - SumNeuron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接