首页 > 解决方案 > 将当前参数传递给循环中的函数

问题描述

我正在使用 D3 打印多个矩形。现在我希望矩形可以允许用户点击它并激活一些功能。

例如,有 3 个矩形"Tom""Mary""Ben"。当用户点击不同的矩形时,它将传递当前值。就像我点击"Tom"它时会传递"Tom"调用该​​函数一样。

但是,我发现打印完矩形后,无论我点击哪个矩形,它们都返回数据集的最小值。

在我的示例中,即使我单击"Tom"or "Mary",都返回"Ben"

for (var i = 0; i < ward_set.length; i++) {
  var ward_id = ward_set[i];
  legend.append("rect")
    .attr("x", legend_x + 180 + 100 * n)
    .attr("y", legend_y)
    .attr("width", 18)
    .attr("height", 18)
    .attr("fill", colors[count])
    .attr("class", "legend" + ward_set[i])
    .on("click", function() {
      console.log(ward_id);
    });
}

标签: javascriptd3.js

解决方案


在编写 D3 代码时,您的问题完美地说明了一个非常重要的原则,一个经验法则,如果您愿意的话:永远不要使用循环来附加元素。请改用进入/更新/退出模式。

当您使用循环(无论是for、等...)时会发生什么whileforEach不仅没有数据绑定,而且您还会遇到您所描述的这种奇怪的结果(始终获得最后一个值),此处对此进行了解释:JavaScript循环内的闭包——简单的实际例子

因此,使用 D3 惯用输入选择的解决方案将是:

const data = ["Tom", "Mary", "Ben"];

const svg = d3.select("svg");

const rects = svg.selectAll(null)
  .data(data)
  .enter()
  .append("rect")
  //etc...

然后,在click侦听器中,您得到第一个参数,即数据:

.on("click", function(d) {
    console.log(d)
})

这是一个演示:

const data = ["Tom", "Mary", "Ben"];

const svg = d3.select("svg");

const rects = svg.selectAll(null)
  .data(data)
  .enter()
  .append("rect")
  .attr("width", 50)
  .attr("height", 150)
  .attr("x", (_, i) => i * 60)
  .on("click", function(d) {
    console.log(d)
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>


推荐阅读