D3.js前端页面OOP重构后点击事件无法调用update方法求助
问题:D3.js OOP重构后click方法无法调用update方法
将基于D3.js的前端代码从函数式重构为面向对象(OOP)后,点击节点触发click方法时,调用this.update(d)出现错误:
Uncaught ReferenceError: this.update is not defined
核心原因是事件回调中this的指向发生了偏移,默认不再指向UpdateTree类的实例。
问题代码
class UpdateTree{ update(source){} enter_new_nodes_at_the_parents_previous_position(node, source){ var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", this.click); } click(d) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } this.update(d); // 此处this指向DOM元素,而非类实例 } }
原因分析
在JavaScript中,DOM事件回调(包括D3的.on绑定的回调)执行时,this默认指向触发事件的DOM元素(此处是<g class="node">),而不是UpdateTree的类实例,因此找不到实例上的update方法。
解决方案
方案1:使用bind绑定this
在绑定点击事件时,通过bind把类实例的this绑定到click方法上,强制回调中的this指向类实例:
enter_new_nodes_at_the_parents_previous_position(node, source){ var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", this.click.bind(this)); // 绑定类实例的this }
方案2:用箭头函数包裹回调
箭头函数的this遵循词法作用域,会继承外层上下文的this(即类实例),可以直接包裹原click方法:
enter_new_nodes_at_the_parents_previous_position(node, source){ var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", (event, d) => this.click(d)); // 箭头函数继承外层this }
注:D3 v6+版本的事件回调第一个参数是事件对象,第二个是数据d,如果需要使用事件对象,可在click方法中添加对应参数。
方案3:在构造函数中提前绑定this
如果click方法需要被多次绑定事件,可在类的构造函数中提前完成this绑定,避免重复操作:
class UpdateTree{ constructor() { this.click = this.click.bind(this); // 提前绑定this到click方法 } update(source){} enter_new_nodes_at_the_parents_previous_position(node, source){ var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", this.click); // 直接使用已绑定好的方法 } click(d) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } this.update(d); } }
内容的提问来源于stack exchange,提问作者Pelle Martin Hesketh
相关产品推荐
相关产品推荐

