阻止div的childNodes响应div的事件监听器

时间:2019-08-12 21:31:58

标签: javascript d3.js

我正在使用d3来显示数据集中的数据。显示屏显示了层次结构的三个元素:

  • 最高级别:“组织维持活动”
  • 中级:“极限运动”
  • 底层:“跳伞管理”

单击代表中间级别的DOM时,将显示最下面的级别。再次单击中间级别时,底部级别消失。一切都很好。

问题是我的用户总是被诱惑点击底层,而这样做却使底层消失了。我希望这样做,以便仅在单击中间层时才使底部层消失。

我尝试过的:

我尝试将事件侦听器放在中间级别的文本元素上,而不是div上。这导致错误d.key is not a function

我也尝试在on.click之前加上div.parentNodedivs2.parentNode,但收到消息divs2.parentNode is undefined.

这是我的代码

var doc = URL.createObjectURL(new Blob([`TooltipInfo	Category	Function1	Function2
Records relating to the skydiving.  Includes halters, parachutes, and altimeters.<ul><li>For records relating to rock climbing, see <b>rock climbing</b>.</li><li>For travel expenses, see <b>Procurements & Purchasing</b>.</li></ul>Retention:<ul><li>Keep records for seven years from the date of record creation, then send to <mark>archives.</mark></li><li>Keep all other records for seven years from the date of record creation, then destroy.</li></ul>	• Skydiving Management	Extreme Sports >	Organization-sustaining Activities`]))


d3.tsv(doc)
  .row(function(d) {
    return {
      University: d.University,
      TooltipInfo: d.TooltipInfo,
      Searchterms: d.Searchterms,
      Category: d.Category,
      Function1: d.Function1,
      Function2: d.Function2,
      MaxRetentionRounded: d.MaxRetentionRounded,
      ModifiedRetention: d.ModifiedRetention
    };
  })
  .get(function(error, data) {

    var div = d3.select("body").append("div")
      .attr("class", "tooltip")
      .style("opacity", 0)

    var height = 150,
      width = 300;


    var nest = d3.nest()
      .key(function(d) {
        return d.Function2;
      })
      .key(function(d) {
        return d.Function1;
      })
      .key(function(d) {
        return d.Category;
      })
      .entries(data);


    var height = 80,
      width = 150;


    var divs = d3.select(".container")
      .selectAll(null)
      .data(nest)
      .enter()
      .append("div")
      .attr("class", "innerdiv");

    divs.append("p")
      .html(function(d) {
        return d.key;

      });



    var divs2 = divs.selectAll(null)
      .data(function(d) {
        return d.values;
      })
      .enter()
      .append('div')
      .attr("class", "first")
      .style("cursor", "pointer")
      .on("click", function(d, i) {
      const curColour = this.childNodes[1].attributes["height"].nodeValue;
      if (curColour == '0px') {
        d3.selectAll(this.childNodes).attr("height", "20px");
      } else if (curColour == '0') {
        d3.selectAll(this.childNodes).attr("height", "20px");
      } else {
        d3.selectAll(this.childNodes).attr("height", "0px");

      }
    });

    divs2.append("text")
      .attr('class', 'label1')
      .attr('x', 0)
      .attr('y', 0)
      .style("font-size", "21px")
      .text(function(d) {
        return d.key;
      })


    var svgs2 = divs2.selectAll(null)
      .data(function(d) {
        return d.values;
      })
      .enter()
      .append('svg')
      .attr("class", "second")
      .attr("height", 0)
      .attr("width", function(d) {
        return String(d3.select(this).value).length * 31.5
      })
    svgs2.append("text")
      .attr('class', 'label2')
      .attr('x', 10)
      .attr('y', 17)
      .style("font-size", "14px")
      .text(function(d) {
        return d.key;
      })
      .attr('text-anchor', 'start')
      .style("cursor", "pointer")
      .on("mouseover", function(d, i) {
        div.transition()
          .duration(200)
          .style("opacity", .9);
        div.html(d3.select(this).datum().values[0].TooltipInfo)

      })
      .on("mouseout", function(d) {
        div.transition()
          .duration(500)
          .style("opacity", 0);
      });

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>

<div class="container"></div>

更新:我已经尝试在子节点上放置“停止传播”:

.on("mouseover", function(event) {
      event.stopPropagation();
      div.transition()
        .duration(200)
        .style("opacity", .9);
      div.html(d3.select(this).datum().values[0].TooltipInfo)

但这似乎阻止了孩子的动作(出现工具提示),而不是阻止了父母的动作(孩子消失)。

UPDATE#2:stopPropagation似乎不适用于mouseover,而仅适用于click。下面给出了我想要的行为(但是我仍然需要弄清楚如何使工具提示消失):

.on("click", function() {
      event.stopPropagation();
      div.transition()
        .duration(200)
        .style("opacity", .9);
      div.html(d3.select(this).datum().values[0].TooltipInfo)

2 个答案:

答案 0 :(得分:1)

当您单击最底层的SVG时,浏览器将尝试为所产生的click事件找到合适的处理程序,该事件从鼠标(最一般而言,指针)位置的最底端元素开始。如果在该元素上未找到处理程序,则浏览器将向上遍历DOM树,检查其中是否包含任何内容。父级-已注册处理程序的元素,直到找到一个处理程序或到达根元素为止。此过程称为事件冒泡,如果您不熟悉它,则可能需要花一些时间来研究这个概念,因为它有助于理解JavaScript事件处理时的许多误解。可以找到涉及此主题的大量资源,例如:

要阻止click事件冒泡到中级元素,从而导致它切换底层元素的可见性,您需要在底层元素本身上注册click处理程序。在该处理程序中,您可以使用事件的stopPropagation方法来防止事件再冒泡。

.on("click", () => d3.event.stopPropagation());

这样做,如果单击底层元素,则不会执行中层元素的处理程序,而如果单击中层元素本身,仍然可以访问它。

看看以下工作演示:

var doc = URL.createObjectURL(new Blob([`TooltipInfo	Category	Function1	Function2
Records relating to the skydiving.  Includes halters, parachutes, and altimeters.<ul><li>For records relating to rock climbing, see <b>rock climbing</b>.</li><li>For travel expenses, see <b>Procurements & Purchasing</b>.</li></ul>Retention:<ul><li>Keep records for seven years from the date of record creation, then send to <mark>archives.</mark></li><li>Keep all other records for seven years from the date of record creation, then destroy.</li></ul>	• Skydiving Management	Extreme Sports >	Organization-sustaining Activities`]))


d3.tsv(doc)
  .row(function(d) {
    return {
      University: d.University,
      TooltipInfo: d.TooltipInfo,
      Searchterms: d.Searchterms,
      Category: d.Category,
      Function1: d.Function1,
      Function2: d.Function2,
      MaxRetentionRounded: d.MaxRetentionRounded,
      ModifiedRetention: d.ModifiedRetention
    };
  })
  .get(function(error, data) {

    var div = d3.select("body").append("div")
      .attr("class", "tooltip")
      .style("opacity", 0)

    var height = 150,
      width = 300;


    var nest = d3.nest()
      .key(function(d) {
        return d.Function2;
      })
      .key(function(d) {
        return d.Function1;
      })
      .key(function(d) {
        return d.Category;
      })
      .entries(data);


    var height = 80,
      width = 150;


    var divs = d3.select(".container")
      .selectAll(null)
      .data(nest)
      .enter()
      .append("div")
      .attr("class", "innerdiv");

    divs.append("p")
      .html(function(d) {
        return d.key;

      });



    var divs2 = divs.selectAll(null)
      .data(function(d) {
        return d.values;
      })
      .enter()
      .append('div')
      .attr("class", "first")
      .style("cursor", "pointer")
      .on("click", function(d, i) {
      const curColour = this.childNodes[1].attributes["height"].nodeValue;
      if (curColour == '0px') {
        d3.selectAll(this.childNodes).attr("height", "20px");
      } else if (curColour == '0') {
        d3.selectAll(this.childNodes).attr("height", "20px");
      } else {
        d3.selectAll(this.childNodes).attr("height", "0px");

      }
    });

    divs2.append("text")
      .attr('class', 'label1')
      .attr('x', 0)
      .attr('y', 0)
      .style("font-size", "21px")
      .text(function(d) {
        return d.key;
      })


    var svgs2 = divs2.selectAll(null)
      .data(function(d) {
        return d.values;
      })
      .enter()
      .append('svg')
      .attr("class", "second")
      .attr("height", 0)
      .attr("width", function(d) {
        return String(d3.select(this).value).length * 31.5
      })
    svgs2.append("text")
      .attr('class', 'label2')
      .attr('x', 10)
      .attr('y', 17)
      .style("font-size", "14px")
      .text(function(d) {
        return d.key;
      })
      .attr('text-anchor', 'start')
      .style("cursor", "pointer")
      .on("mouseover", function(d, i) {
        div.transition()
          .duration(200)
          .style("opacity", .9);
        div.html(d3.select(this).datum().values[0].TooltipInfo)

      })
      .on("mouseout", function(d) {
        div.transition()
          .duration(500)
          .style("opacity", 0);
      })
      .on("click", () => d3.event.stopPropagation());

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>

<div class="container"></div>

答案 1 :(得分:-1)

答案是三个不同元素的组合:

  1. 将事件监听器从鼠标悬停更改为点击。这个 允许您..
  2. 在子div上添加stopPropagation
  3. 一旦摆脱了鼠标悬停,就无法再使用“ mouseout”来 关闭工具提示。您需要在on.click中添加一个条件 功能。请参见下面的完整示例。

var doc = URL.createObjectURL(new Blob([`TooltipInfo	Category	Function1	Function2
Records relating to the skydiving.  Includes halters, parachutes, and altimeters.<ul><li>For records relating to rock climbing, see <b>rock climbing</b>.</li><li>For travel expenses, see <b>Procurements & Purchasing</b>.</li></ul>Retention:<ul><li>Keep records for seven years from the date of record creation, then send to <mark>archives.</mark></li><li>Keep all other records for seven years from the date of record creation, then destroy.</li></ul>	• Skydiving Management	Extreme Sports >	Organization-sustaining Activities`]))


d3.tsv(doc)
  .row(function(d) {
    return {
      University: d.University,
      TooltipInfo: d.TooltipInfo,
      Searchterms: d.Searchterms,
      Category: d.Category,
      Function1: d.Function1,
      Function2: d.Function2,
      MaxRetentionRounded: d.MaxRetentionRounded,
      ModifiedRetention: d.ModifiedRetention
    };
  })
  .get(function(error, data) {

    var div = d3.select("body").append("div")
      .attr("class", "tooltip")
      .style("opacity", 0)

    var height = 150,
      width = 300;


    var nest = d3.nest()
      .key(function(d) {
        return d.Function2;
      })
      .key(function(d) {
        return d.Function1;
      })
      .key(function(d) {
        return d.Category;
      })
      .entries(data);


    var height = 80,
      width = 150;


    var divs = d3.select(".container")
      .selectAll(null)
      .data(nest)
      .enter()
      .append("div")
      .attr("class", "innerdiv");

    divs.append("p")
      .html(function(d) {
        return d.key;

      });



    var divs2 = divs.selectAll(null)
      .data(function(d) {
        return d.values;
      })
      .enter()
      .append('div')
      .attr("class", "first")
      .style("cursor", "pointer")
      .on("click", function() {
        const curColour = this.childNodes[1].attributes["height"].nodeValue;
        if (curColour == '0px') {
          d3.selectAll(this.childNodes).attr("height", "20px");
        } else if (curColour == '0') {
          d3.selectAll(this.childNodes).attr("height", "20px");
        } else {
          d3.selectAll(this.childNodes).attr("height", "0px");

        }
      }, false);

    divs2.append("text")
      .attr('class', 'label1')
      .attr('x', 0)
      .attr('y', 0)
      .style("font-size", "21px")
      .text(function(d) {
        return d.key;
      })

    var firstClick = 1;

    var svgs2 = divs2.selectAll(null)
      .data(function(d, e) {
        return d.values;
      })
      .enter()
      .append('svg')
      .attr("class", "second")
      .attr("height", 0)
      .attr("width", function(d) {
        return String(d3.select(this).value).length * 31.5
      })
    svgs2.append("text")
      .attr('class', 'label2')
      .attr('x', 10)
      .attr('y', 17)
      .style("font-size", "14px")
      .text(function(d) {
        return d.key;
      })
      .attr('text-anchor', 'start')
      .style("cursor", "pointer")
      .on("click", function() {
        event.stopPropagation()
        if (firstClick % 2 === 1) {
          div.transition()
            .duration(200)
            .style("opacity", .9)
          div.html(d3.select(this).datum().values[0].TooltipInfo)

          console.log(firstClick);
        } else {
          div.style("opacity", 0)
        }
        firstClick++;
      })

  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div class="container"></div>