在单击事件侦听器中添加第二个单击事件侦听器

Adding second click event listener within a click event listener

我尝试使用 D3 在现有的点击事件监听器中添加第二个点击事件监听器,但没有成功。

基本上,我有一张事件地图(圆圈)。我希望用户能够点击一个圆圈并弹出 window 出现。我希望该弹出窗口仅在用户第二次单击任何地方时消失。因此,单击一个圆圈将实例化弹出窗口并绑定它,第二次单击“任何地方”将使弹出窗口消失并将圆圈恢复为仅响应悬停,除非再次单击。

我通过在圆圈事件监听器中添加另一个 "body" 单击事件监听器来解决这个问题:

  // event listener: if events (circles) are clicked, instantiate pop-up
  d3.selectAll(".events").on("click", function(d) { 
        console.log("event clicked!")
         //disable hover event listeners
         d3.selectAll(".events").on("mouseout", null);
         d3.selectAll(".events").on("mouseover", null);              
              popup.transition()        
                 .duration(200)      
                .style("opacity", .9);
              popup.html(d.ArtistBio)

        // if user clicks a SECOND time, anywhere, make popup disappear
        d3.select("body").on("click", function(d) { 
            console.log("body clicked")
            //hide popup
            popup.transition()        
                  .duration(200)      
                  .style("opacity", 0);  
            //revert back to hover, unless user clicks again!
            d3.selectAll(".events").on("mouseout", true);
            d3.selectAll(".events").on("mouseover", true);
            d3.selectAll(".events").on("mouseout", function(d) { 
            console.log("mousing out!")      
                popup.transition()        
                  .duration(200)      
                  .style("opacity", 0);              
              })

            // mouseover event listers added back in
            d3.selectAll(".events").on("mouseover", function(d) { 
              popup.transition()        
                 .duration(200)      
                .style("opacity", .9);
              popup.html(d.ArtistBio)

          })            
        })

我的问题是这两个事件同时触发,而不是按顺序触发:一旦我点击一个圆形事件,body click 事件侦听器也被实例化,因此弹出窗口被删除一旦它被渲染。有没有办法以类似于我上面描述的方式来做我想做的事情?提前致谢。

你可以这样做:

  // event listener: if events (circles) are clicked, instantiate pop-up
  d3.selectAll(".events").on("click", function(d) { 
        console.log("event clicked!")
        const currentCircle = this; 
        //disable hover event listeners
         d3.selectAll(".events").on("mouseout", null);
         d3.selectAll(".events").on("mouseover", null);              
              popup.transition()        
                 .duration(200)      
                .style("opacity", .9);
              popup.html(d.ArtistBio)
        // if user clicks a SECOND time, anywhere, make popup disappear
        d3.select("body").on("click", function(d) { 
    if(this !== currentCircle){
            console.log("body clicked")
            //hide popup
            popup.transition()        
                  .duration(200)      
                  .style("opacity", 0);  
            //revert back to hover, unless user clicks again!
            d3.selectAll(".events").on("mouseout", true);
            d3.selectAll(".events").on("mouseover", true);
            d3.selectAll(".events").on("mouseout", function(d) { 
            console.log("mousing out!")      
                popup.transition()        
                  .duration(200)      
                  .style("opacity", 0);              
              })

            // mouseover event listers added back in
            d3.selectAll(".events").on("mouseover", function(d) { 
              popup.transition()        
                 .duration(200)      
                .style("opacity", .9);
              popup.html(d.ArtistBio)

          })
       }            
        })

在 body 事件侦听器中,检查单击的元素是否与当前 circle/popup 单击的元素不同。

点击会冒泡,这在意料之中。为避免这种情况,请使用 event.stopPropagation。您还可以使用 d3.events(当它们存在时...):

d3.event.stopPropagation();

这里是演示,点击矩形和外面:

d3.select("rect").on("click", function() {
  console.log("rectangle clicked");
  d3.event.stopPropagation();
  d3.select("body").on("click", function() {
    console.log("body clicked")
  })
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg>
  <rect width="50" height="50" x="100" y="50"></rect>
</svg>