我需要一些帮助来理解我的小代码中发生的情况。在我的网络应用程序中,我使用 D3.js 绘制一些我称之为标记的形状。可以在屏幕上拖动标记,每次拖动时我都会确定其位置,进行一些计算并更新分配给该标记的数据对象。让我告诉你:
class Marker {
constructor(name) {
this.name = name;
this.computedStuff = 0;
}
getDisplayName() {
return 'Marker ' + this.name;
}
}
this.markerValues = {
'm1': new Marker('m1'),
'm2': new Marker('m2')
}
this.svg.selectAll('g.marker')
.data(_.values(this.markerValues))
.join(enter => {
const group = enter.append('g');
group.append('path')
.attr('d', 'M -12.867771,6.1070093 V 13.761566 H 12.867771 '
+ 'V 6.1070093 H 6.4338855 '
+ 'L 0,-1.1321257 -6.4338856,6.1070093 Z')
.attr('transform', `translate(0 120) scale(2)`)
.attr('stroke', 'black')
.attr('stroke-width', '1px')
.attr('fill', '#fff')
.on('dblclick', d => console.log(d));
group.append('text')
.attr('y', 120)
.text(d => d.getDisplayName())
.style('font-size', '10px')
.style('fill', 'black');
return group;
})
.attr('class', 'marker')
.call(d3.drag()
.on('drag', function (d) {
// Computation here
d.computedStuff = computedAbove;
// Here is a typical code for moving a marker according to
// d3.event.
})
);
问题出在:.on('dblclick', d => console.log(d));
。这看起来非常简单——双击,记录数据内容;在我移动标记之前它“工作”得很好。移动标记时,compatedStuff 变量会因计算而更改,但随后双击路径会在控制台中记录旧值,就好像对象根本没有更改一样。我 100% 确定它已更改,因为我检查了 this.markerValues
对象的内容。事件处理程序看起来好像已附加了对象的副本,并且记录了该副本而不是原始对象。
但是...
当我从路径中删除此事件处理程序并将其附加到组时:group.on('dblclick', d => console.log(d));
,然后它就可以工作了!我可以移动标记,双击它,并且始终会提供有效值。
为什么组处理程序始终提供有效数据,而附加到组子级的处理程序则保留某种副本或未引用的对象?
最佳答案
简单的解决方案是:不要使用粗箭头 .on('dblclick', d => console.log(d));
改用经典符号
.on('dblclick', function(d) { console.log(d) });
d3 设置处理程序中 this
的范围以引用所引用的节点。使用粗箭头会覆盖词法范围。
但是,如果您使用完整的处理程序签名并按索引引用当前节点,则可以在处理程序中使用粗箭头:
selection.on('dblclick', (d, i, nodes) => {
console.log(nodes[i])
});
this article中有一个不错的解释
关于javascript - D3.js 在 "on"事件中丢失对象引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59930964/