如何重新启用点击事件?

时间:2019-08-15 06:46:46

标签: javascript d3.js event-handling

我想在矩形上禁用onclick事件,但是如何再次单击启用它?

我认为我需要使用矩形的onclick属性,但每次都使用null值。

const svgViewport = d3.select("body")
  .append("svg")
  .attr("width", 150)
  .attr("height", 150);

let myData = [
  [{
      x: 30,
      y: 40
    },
    {
      x: 30,
      y: 60
    }
  ],
  [{
      x: 60,
      y: 40
    },
    {
      x: 60,
      y: 60
    }
  ],
  [{
      x: 90,
      y: 40
    },
    {
      x: 90,
      y: 60
    }

  ],
  [{
      x: 120,
      y: 40
    },
    {
      x: 120,
      y: 60
    }
  ]
];

let buttons = [{
    x: 40,
    y: 100
  },
  {
    x: 70,
    y: 100
  },
  {
    x: 100,
    y: 100
  }
];


const groups = svgViewport.selectAll(null)
  .data(myData)
  .enter()
  .append("g");

const circles = groups.selectAll(null)
  .data(d => d)
  .enter()
  .append("circle")
  .attr("cx", (d) => d.x)
  .attr("cy", (d) => d.y)
  .attr("r", 10);

const button = svgViewport.selectAll("g")
  .data(buttons)
  .append("rect")
  .attr("x", (d) => d.x)
  .attr("y", (d) => d.y)
  .attr("class", "btn")
  .attr("id", (d, i) => "a" + i)
  .attr("cursor", "pointer")
  .attr("width", 10)
  .attr("height", 10)
  .attr("fill", "red")
  .on("click", (d, i) => {
    let el = document.getElementsByClassName("btn")[i].id;
    console.log("you clicked on button with id=" + el);
    svgViewport.selectAll("#" + el).on("click", null);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

我想使用d3.js启用/禁用我的矩形,据我所知按钮无法附加到svg

1 个答案:

答案 0 :(得分:1)

起初,您的问题尚不清楚,但是我相信您在your comment中解释了您想要的内容:

  

我希望为每次偶数和奇数点击提供不同的功能

在这种情况下,您不需要附加/分离事件处理程序(这使您的问题成为经典的XY problem)。取而代之的是,我们创建一个计数器并根据计数器是奇数还是偶数来运行不同的功能。

为此,我们将创建一个closure

首先,在回调中立即调用侦听器函数:

button.on("click", clickButtons());

这对于创建闭包很重要,因为与仅引用函数不同……

button.on("click", clickButtons);

...是最常见的方法,通过调用侦听器函数并获取其返回值,我们将返回另一个函数(见下文)。

现在有了监听器功能:

function clickButtons() {
  let counter = 0;
  return function(d, i, n) {
    if (++counter % 2) {
      console.log("You clicked on a button with id " + n[i].id)
    } else {
      console.log("click skipped!")
    }
  }
}

这就是它的作用:

首先,它声明一个counter,并将其设置为0。此counter可在内部函数中访问,该函数实际上已返回。因此,selection.on传递的三个参数被该内部函数捕获:

return function(d, i, n) {
//arguments-----^--^--^

这些参数,基准面,索引和组是您在函数中执行任何操作的基础。

然后是重要的部分:每次单击时,您增加counter并测试其除以2的余数,这仅返回两个值,1(truthy)和0 (虚假):

if (++counter % 2) {
    //do stuff here for odd counter
} else {
   //do stuff here for even counter
};

这是演示:元素的ID仅在您单击红色按钮时每隔一次显示一次:

const svgViewport = d3.select("body")
  .append("svg")
  .attr("width", 150)
  .attr("height", 150);

let myData = [
  [{
      x: 30,
      y: 40
    },
    {
      x: 30,
      y: 60
    }
  ],
  [{
      x: 60,
      y: 40
    },
    {
      x: 60,
      y: 60
    }
  ],
  [{
      x: 90,
      y: 40
    },
    {
      x: 90,
      y: 60
    }

  ],
  [{
      x: 120,
      y: 40
    },
    {
      x: 120,
      y: 60
    }
  ]
];

let buttons = [{
    x: 40,
    y: 100
  },
  {
    x: 70,
    y: 100
  },
  {
    x: 100,
    y: 100
  }
];


const groups = svgViewport.selectAll(null)
  .data(myData)
  .enter()
  .append("g");

const circles = groups.selectAll(null)
  .data(d => d)
  .enter()
  .append("circle")
  .attr("cx", (d) => d.x)
  .attr("cy", (d) => d.y)
  .attr("r", 10);

const button = svgViewport.selectAll("g")
  .data(buttons)
  .append("rect")
  .attr("x", (d) => d.x)
  .attr("y", (d) => d.y)
  .attr("class", "btn")
  .attr("id", (d, i) => "a" + i)
  .attr("cursor", "pointer")
  .attr("width", 10)
  .attr("height", 10)
  .attr("fill", "red")
  .on("click", clickButtons());

function clickButtons() {
  let counter = 0;
  return function(d, i, n) {
    if (++counter % 2) {
      console.log("You clicked on a button with id " + n[i].id)
    } else {
      console.log("click skipped!")
    }
  }
}
.as-console-wrapper { max-height: 30% !important;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>