D3回调函数的“ this”遮盖了对象的“ this”

时间:2018-12-18 18:30:29

标签: javascript typescript d3.js

我有一个包装D3的课程。我将其转换为TypeScript,但遇到了以下两个错误,无法弄清楚如何解决它们(实际上存在多个错误,但它们都与此对相似),

src/d3-graph.ts:295:19 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. 
295         d3.select(this)
                      ~~~~

  src/d3-graph.ts:294:23
    294       .on('mouseout', function(d: any) {
                              ~~~~~~~~
    An outer value of 'this' is shadowed by this container.

代码(类中的一种方法,其中添加了行号以供参考)

...
1 private _enableNodeHighlightOnHover() {
2   this._nodes
3     .on('mouseout', function(d: any) {
4       d3.select(this)
5         .style('stroke-width', '2px')
6     })
7 }
...

第2行的通知,this引用了该类的实例对象。

在第4行上,this引用对象D3已绑定到提供给on的回调中(第3行)。还要注意,在function上使用(...) => { ... } -允许D3将this绑定到它需要的对象。

如果我可以通过其他方式访问在this中使用的D3对象,我很高兴在回调函数中失去d3.select(this)的使用。但是我不确定那会是什么。

此模式还有其他用途,

private _enableDrag() {
  const that = this

  this._drag = d3.drag()
  this._drag
    .on('drag', function(d: any) {
      d.x += d3.event.dx
      d.y += d3.event.dy

      d3.select(this)
        .attr('cx', d.x)
        .attr('cy', d.y)

      that._links.each(function(l: any) {
        if (l.source === d.id)
          d3.select(this)
            .attr('x1', d.x)
            .attr('y1', d.y)
        else if (l.target === d.id)
          d3.select(this)
            .attr('x2', d.x)
            .attr('y2', d.y)
      })

      if (that._nodeTextLabels === null)
        logger.warn(
          'enableDrag called before this._nodeTextLabels has been initialized')
      else
        that._nodeTextLabels.each(function(n: any) {
          if (n.id == d.id)
            d3.select(this)
              .attr('x', d.x + D3Graph._LABEL_FONT_SIZE / 2)
              .attr('y', d.y + 15)
        })

      that._nodes.each(function(n: any) {
        if (n.id == d.id)
          d3.select(this).select('circle')
            .attr('cx', d.x)
            .attr('cy', d.y)
      })
    })
}

2 个答案:

答案 0 :(得分:2)

作为this的替代方法,请尝试使用侦听器函数的第二个和第三个参数:

  function(d,i,group) { d3.select(group[i] ... })

之所以行之有效,是因为使用selection.on("event",function(){})selection.each(function() {})时,d3将当前元素绑定到this上以提供所提供的功能。 D3还将三个参数绑定到所提供的函数:

  • 当前基准(d
  • 当前索引(i
  • 选择中的元素组,而不是元素的选择(此处命名为group

使用时:

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

您实际上在执行以下操作:

selection.on("event", function(d,i,group) { d3.select(group[i]); })

由于group包含选择的元素,而i是当前索引,group[i]是当前元素,与this相同。

使用group[i]允许使用箭头功能和环境,这些功能可能会在仍然访问当前元素的同时改变this的上下文。

答案 1 :(得分:1)

使用eachmap等在cheerio上也会发生此错误。

TypeScript(>=2.0)可以指定函数的这种类型。以下代码可以避免 TS2683 错误。 https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters

.on('mouseout', function(this: any, d: any) {

})