当`this`不可用时,从拖动回调中检索DOM目标

4
d3.drag 的文档表示,在回调函数中可以使用 this 来获取被拖动事件的 DOM 元素:

当指定的事件被触发时,每个监听器都将使用与 selection.on 监听器相同的上下文和参数进行调用:当前数据 d 和索引 i,this 上下文为当前的 DOM 元素。

但是我的回调函数是一个对象实例,this 指向该对象。因此我需要另一种获取通常由 this 传递的当前 DOM 元素的方法。我该怎么做?

1个回答

12

使用第二个和第三个参数一起来获取thisthis不可用时:

d3.drag().on(typename, function(d, i, n) {
  //here, 'this' is simply n[i]
})

为了详细说明,可以查看下面我写的关于箭头函数中this的处理文章。虽然问题不同,但解释是一样的。

这里有一个基本演示,请尝试拖动圆圈并查看控制台:

var data = d3.range(5)
var svg = d3.select("body")
  .append("svg")
  .attr("width", 400)
  .attr("height", 100);
var circle = svg.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("cy", 50)
  .attr("cx", function(d) {
    return 50 + 50 * d
  })
  .attr("r", 10)
  .attr("fill", "tan")
  .attr("stroke", "black")
  .call(d3.drag()
    .on("start", function(d, i, n) {
      console.log(JSON.stringify(n[i]))
    }))
<script src="https://d3js.org/d3.v4.min.js"></script>

PS:因为在 Stack Snippets 中尝试对 D3 selection 进行 console.log 会导致冻结,所以我在 D3 selection 上使用了 JSON.stringify


箭头函数中使用 "this"

D3.js 中的大多数函数都接受一个匿名函数作为参数。常见的示例包括 .attr, .style, .text, .on.data,但是列表远不止这些。

在这种情况下,匿名函数将依次针对每个选定的元素进行评估,并传递:

  1. 当前数据 (d)
  2. 当前索引 (i)
  3. 当前组 (nodes)
  4. this 作为当前 DOM 元素。

datum、index 和 current group 都作为参数传递,这是 D3.js 中著名的第一个、第二个和第三个参数(在 D3 v3.x 中,它们的参数通常被命名为 dip)。然而,为了使用 this,不需要使用任何参数:

.on("mouseover", function(){
    d3.select(this);
});

当鼠标悬停在元素上方时,上述代码将选择this。可以在此fiddle中检查其工作情况:https://jsfiddle.net/y5fwgopx/

箭头函数

作为新的ES6语法,箭头函数与函数表达式相比具有更短的语法。然而,对于一个经常使用this的D3程序员来说,它存在一个陷阱:箭头函数不会创建自己的this上下文。这意味着,在箭头函数中,this具有其来自封闭上下文的原始含义。

这在几种情况下可能很有用,但对于习惯于在D3中使用this的编码人员来说,这是一个问题。例如,使用上面的fiddle中的相同示例,以下代码将不起作用:

.on("mouseover", ()=>{
    d3.select(this);
});

如果您怀疑,这里有一个示例:https://jsfiddle.net/tfxLsv9u/

这并不是大问题:需要时可以使用常规的函数表达式。但是如果要编写所有代码均使用箭头函数呢?是否可能在 D3 中使用箭头函数并仍正确地使用 this

答案是肯定的,因为 this 相当于 nodes[i]。实际上,在描述此内容时,D3 API 中随处可见提示:

...其中this为当前 DOM 元素(nodes[i]

解释很简单:由于nodes是DOM中当前元素组,i是每个元素的索引,因此nodes[i]指代的就是当前DOM元素本身。也就是说,this

因此,可以使用以下代码:

.on("mouseover", (d, i, nodes) => {
    d3.select(nodes[i]);
});

这里是相应的代码片段:https://jsfiddle.net/2p2ux38s/


.on("mouseover", (d, i, nodes) => { d3.select(nodes[i]); });这是在d3 V4中可用的代码。 我们如何在d3 v3中实现这个? - Ajinkya Dhote
4
请执行以下操作:.on("mouseover", ()=>{d3.select(d3.event.target);})。这段代码的作用是在鼠标悬停时选择d3事件的目标元素。 - Gerardo Furtado
我尝试了jsfiddle。它给出了与我现在得到的相同的错误。可能是由于版本更改或其他原因。 - krishna
@krishna 嗯,这不是一个downvote的理由,因为我的答案在这里显然是正确的:你做错了其他事情。如果你有问题,我建议你发布一个重现它的问题。 - Gerardo Furtado

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