将事件侦听器添加到动态创建的元素中

时间:2019-10-12 10:11:45

标签: javascript d3.js addeventlistener

在尝试为使用香草JS呈现的某些foreignObject添加点击事件监听器时,我目前遇到一些问题。

当我使用内置的d3 on click函数时,它可以工作,但我更希望使用javascript代码来完成它。

但是,该函数从不触发这些元素,我也不明白为什么。

该代码示例并不完整,但应突出显示我正在尝试做的事情。

var nodes = g.selectAll("foreignObject")
    .data(response.nodes)
    .enter()
    .append("foreignObject")
    .attr("x", function(d) {
        return d.x - nodeWidth / 2;
    })
    .attr("y", function(d) {
        return d.y - nodeHeight / 2;
    })
    .attr("width", nodeWidth)
    .attr("height", nodeHeight)
    .append("xhtml:div")
    .attr("class", "outer")
    .html(function(d) { 
        var nodeHtml = createNodeElement(d);
        return nodeHtml.outerHTML;
    })
   // If I append the img like this, it works, but ends up in the wrong "element scope"
   .append("img")
        .attr("class", "optionsImg")
        .attr("src","/images/options-squares.svg")
        .on("click", function(d) {
            currentTooltipObject = d;
            renderTooltipDiv();
        });


function createNodeElement(d) {
    let nodeElement = document.createElement("div");
    nodeElement.className = "nodeElement";
    let nodeOptionsImg = document.createElement("img");
    nodeOptionsImg.className = "nodeOptionsImg";
    nodeOptionsImg.src = "/images/options-squares.svg";
    nodeOptionsImg.addEventListener("click", function() {
        console.log("Clicked on optionsImg for this object: "+d);
    });
    nodeElement.appendChild(nodeOptionsImg);
    return nodeElement;
}

2 个答案:

答案 0 :(得分:0)

您的方法的主要问题在于,使用outerHTMLinnerHTML.html()内部使用)创建/移动/复制元素的过程有点像序列化和反序列化HTML DOM树。这适用于HTML元素本身,但是,它不保留事件侦听器。因此,在此过程中,您附加到函数createNodeElement中的元素的侦听器将丢失。这是其他问题的变体,例如"Is it possible to append to innerHTML without destroying descendants' event listeners?"

如果您退后一步,重新阅读D3 API docs,您将意识到您实际上已经存在了:D3提供了将本机DOM节点附加到选择内容的方法:

  

选择追加类型<>

     

如果指定的 type 是一个函数,则会为每个选定元素求值,依次传递当前基准( d ),当前索引(< em> i )和当前组( nodes ),其中 this 作为当前DOM元素( nodes [ i ])。此函数应返回要附加的元素。

如果您希望坚持使用createNodeElement的实现以使用本机JS方法创建元素,则可以将该函数简单地传递给selection.append(),因为它会返回一个新创建的节点及其节点。 <img>个子节点。因此,您的代码可以简化为:

var nodes = g.selectAll("foreignObject")
    /* styling omitted */
  .append("xhtml:div")
    .attr("class", "outer")
  .append(createNodeElement);

因为仅对DOM节点的引用传递给所有附加到元素的事件侦听器,因此也会保留。

答案 1 :(得分:-1)

ExpiresByType text/html "access 1 month" ExpiresDefault "access 1 month" 中,createNodeElement函数中的nodeOptionsImg元素尚未呈现。侦听器只能添加到渲染的元素。