ES6函数中this指向问题:Angular+D3拖拽事件无法获取正确this
解决Angular指令中D3拖拽回调的this指向问题
这个问题其实是D3和ES6类结合时的常见坑——D3的拖拽回调函数里,默认的this指向的是被拖拽的DOM元素(也就是你画的那个circle),而不是你的CanvasDirective类实例。这就是为什么你直接用this访问类里的属性/方法会出错,Selection.select(this)也选不到你想要的内容。
下面给你几个可行的解决方案,结合你的代码来调整:
方案1:用箭头函数保留类的this,配合D3事件对象获取拖拽元素
箭头函数不会绑定自己的this,它会继承外层作用域的this(也就是你的类实例)。同时可以通过d3.event对象获取拖拽相关的信息,包括目标元素:
private drawPoints(points: Point[]) { points.forEach(point => { this.svg.append('circle') .attr('r', point.color ? 20 : 10) .attr('cx', point.x) .attr('cy', point.y) .attr('fill', point.color ? point.color : 'lightgray') .attr('stroke-width', !point.color ? 2 : 0) .attr('stroke', !point.color ? 'gray' : '') .call(Drag.drag() .on('drag', () => { // 这里的this是CanvasDirective的类实例 const draggedElement = Selection.select(d3.event.target); // 获取当前拖拽的坐标 const currentX = d3.event.x; const currentY = d3.event.y; // 更新被拖拽圆形的位置 draggedElement.attr('cx', currentX).attr('cy', currentY); // 直接访问类内属性,比如this.config console.log('当前配置信息:', this.config); }) ); }); }
方案2:提前保存类的this到变量,区分DOM元素的this
在forEach里先把类实例的this存到一个变量(比如self),回调里用self访问类属性,用原生this访问被拖拽的DOM元素:
private drawPoints(points: Point[]) { const self = this; // 保存类实例的this points.forEach(point => { this.svg.append('circle') .attr('r', point.color ? 20 : 10) .attr('cx', point.x) .attr('cy', point.y) .attr('fill', point.color ? point.color : 'lightgray') .attr('stroke-width', !point.color ? 2 : 0) .attr('stroke', !point.color ? 'gray' : '') .call(Drag.drag() .on('drag', function() { // 这里的this是被拖拽的circle DOM元素 const draggedElement = Selection.select(this); const currentX = Drag.event.x; const currentY = Drag.event.y; draggedElement.attr('cx', currentX).attr('cy', currentY); // 用self访问类实例的属性和方法 self.emitConfig.emit(self.config); }) ); }); }
方案3:针对D3 v6+的适配(如果你的版本是v6及以上)
如果你的D3是v6版本,d3.event已经被移除,拖拽信息会通过回调参数传递,调整方式如下:
private drawPoints(points: Point[]) { points.forEach(point => { this.svg.append('circle') // ... 圆形属性设置 .call(Drag.drag() .on('drag', (event) => { // event包含拖拽的所有信息 const draggedElement = Selection.select(event.target); const currentX = event.x; const currentY = event.y; draggedElement.attr('cx', currentX).attr('cy', currentY); // 类实例的this依然可以直接访问 console.log('当前参数:', this.param); }) ); }); }
关键说明
- 核心区别是:D3回调里的原生
this默认绑定DOM元素,而ES6类的方法需要访问类实例的this,所以需要通过箭头函数、变量保存、bind绑定这几种方式来区分两者的this指向。 - 你之前尝试的
Selection.select(this)无效,是因为回调里的this已经是DOM元素,不需要再用select包裹,直接操作或者用d3.event.target选中即可。
内容的提问来源于stack exchange,提问作者Michael W. Czechowski
相关产品推荐
相关产品推荐

