D3可缩放图表封装为类时zoom事件this作用域指向异常问题
D3 类封装缩放事件this指向异常解决方案
你遇到的问题核心是D3事件回调默认会将this绑定到触发事件的DOM元素上,覆盖了类实例的上下文,以下是生产环境常用的最优解决方案:
方案1:用箭头函数定义事件回调方法(最简洁推荐)
箭头函数的this继承自定义时的外层作用域,不会被D3动态修改,直接修改zoomed_方法的定义形式即可:
class Timeline { // 其他类逻辑不变 zoomed_ = () => { // 此处this稳定指向类实例,可正常访问scaleX_、gX_等属性 let newXScale = d3.event.transform.rescaleX(this.scaleX_); let newYScale = this.scaleY_; // 更新坐标轴(注意你原代码存在笔误,Y轴应绑定到gY_容器) this.gX_.call(this.AxisX_.scale(newXScale)); this.gY_.call(this.AxisY_.scale(newYScale)); } }
方案2:构造函数内提前绑定上下文
如果不想修改方法的定义形式,可以在类初始化时手动将方法的this绑定到实例:
class Timeline { constructor() { // 其他初始化逻辑 // 提前绑定zoomed_的上下文为当前实例 this.zoomed_ = this.zoomed_.bind(this); this.canvas_.call(d3.zoom() .scaleExtent([.1, 20000]) .extent([[0, 0], [width, height]]) .on('zoom', this.zoomed_)); } zoomed_() { // 原有逻辑不变,this已被提前绑定为类实例 let newXScale = d3.event.transform.rescaleX(this.scaleX_); let newYScale = this.scaleY_; this.gX_.call(this.AxisX_.scale(newXScale)); this.gY_.call(this.AxisY_.scale(newYScale)); } }
方案3:事件绑定时用箭头函数包裹
如果仅需要临时修改单个回调的上下文,也可以在绑定zoom事件时用箭头函数包裹回调:
this.canvas_.call(d3.zoom() .scaleExtent([.1, 20000]) .extent([[0, 0], [width, height]]) .on('zoom', () => this.zoomed_()));
注意事项
如果你的项目使用D3 v6及以上版本,全局d3.event已被废弃,事件对象会作为回调的第一个参数传入,需要对应调整代码:
zoomed_ = (event) => { let newXScale = event.transform.rescaleX(this.scaleX_); // 其余逻辑不变 }
内容的提问来源于stack exchange,提问作者elelias
相关产品推荐
相关产品推荐

