将EventListener 添加到innerHTML

Posted

技术标签:

【中文标题】将EventListener 添加到innerHTML【英文标题】:addEventListener to innerHTML 【发布时间】:2020-11-22 01:30:33 【问题描述】:

我是 javascript 新手,我尝试为每张卡片上的每个按钮添加一个事件侦听器,但代码使最后一张卡片(按钮)只有事件“点击”,所以有什么方法可以让它发生内部html卡片 这是代码:

let tracksRender = (track) => 

track.forEach(element => 

    //this the card that will add the button for
    let card = `<div class="card">
    <div class="image">
        <img class="image_img" src="$element.artwork_url || 'http://lorempixel.com/100/100/abstract/'">
    </div >
        <div class="content">
            <div class="header">
                <a href="$element.permalink_url" target="_blank">$element.title</a>
            </div>
        </div>
</div >`;
    
    //here i add the card to DOM
    let searchResults = document.querySelector('.js-search-results');
    searchResults.innerHTML += card;

    // store the content of the button 
    let inBtn = `<i class="add icon"></i>
    <span>Add to playlist</span>`;
 
    // created button container 
    let btn = document.createElement("div");
    btn.classList.add("ui", "bottom", "attached", "button", "js-button");

    // added the content of the button 
    btn.innerHTML += inBtn;
    
    // here i add the the event Listener to the button 
    btn.addEventListener('click', () => 
        console.log("click");
    );

    //here i add the button to the last card have been created
    searchResults.querySelector(".card:last-child").append(btn);
    
);

和结构:

<!doctype html>
<html>

<head>
    <meta charset='utf-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>SoundCloud Player</title>
    <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css'>
    <link rel='stylesheet' href='styles/main.css'>
    <style></style>
</head>

<body id="soundcloud-player">

    <div class="ui container col">
        <div class="col">
            <div class="main">
                <div class="js-search-results search-results ui cards">

                </div>
            </div>
        </div>
    </div>
    <script src="https://connect.soundcloud.com/sdk/sdk-3.3.2.js"></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js'></script>
    <script src="javascript/main.js"></script>
</body>

</html>

小提琴:https://jsfiddle.net/y73bstju/7/

但它只会将事件添加到最后一张卡片

【问题讨论】:

你可以为你的问题创建一个 Fiddle 吗?谢谢。 @LajosArpad 对不起,我不明白。 有一个名为 jsfiddle.net 的网站,您可以在其中为您的问题创建一个最小的可重现示例。然后我们可以访问它并查看问题所在,这将使解决问题变得容易得多。 @LajosArpad 这是链接 (jsfiddle.net/y73bstju/7),谢谢 【参考方案1】:

创建元素而不是附加 innerHTML 可能会有所帮助:

let tracksRender = (track) => 
    
  // Select the results here, so you wont have to repeat it
  const searchResults = document.querySelector('.js-search-results');

  track.forEach(element => 

    // Create the card, give it its class and innerHTML
    const card = document.createElement('div');
    card.className = 'card';
    card.innerHTML = `<div class="image">
                          <img class="image_img" src="$element.artwork_url || 'http://lorempixel.com/100/100/abstract/'">
                      </div >
                      <div class="content">
                          <div class="header">
                              <a href="$element.permalink_url" target="_blank">$element.title</a>
                          </div>
                     </div>`;
 
    // Created the button, give its classes and innerHTML
    const btn = document.createElement('div');
    btn.className = 'ui bottom attached button js-button';
    btn.innerHTML = '<i class="add icon"></i><span>Add to playlist</span>';
    
    // Add the event listener
    btn.addEventListener('click', () => 
        console.log('click');
    );

    // Append the button to the created card
    card.appendChild(btn);

    // Add the card to the results
    searchResults.appendChild(card);
    
  );


【讨论】:

这是我的想法之一,但它只会为第一个按钮添加事件,谢谢【参考方案2】:

我同意你的观点,理论上对象应该有事件,但我们遇到的行为是,每当在 DOM 的相关部分发生另一个写入时,事件处理程序就会丢失,这就是最后一个元素具有点击事件。所以,让我们先写入 DOM,只有当我们完成之后,我们才应该添加事件监听器,比如:

let SoundCloudAPI = ;
SoundCloudAPI.init = () => 
    SC.initialize( client_id: 'cd9be64eeb32d1741c17cb39e41d254d' );
;
SoundCloudAPI.init();


SoundCloudAPI.getTrack = (inputVlue) => 
    SC.get('/tracks', 
        q: inputVlue
    ).then((tracks) => 
            console.log(tracks);
        SoundCloudAPI.renderTracks(tracks);
    );

SoundCloudAPI.getTrack("alan walker");

SoundCloudAPI.renderTracks = (track) => 

        track.forEach(element => 

    //this the card that will add the button for
    let card = `<div class="card">
    <div class="image">
        <img class="image_img" src="$element.artwork_url || 'http://lorempixel.com/100/100/abstract/'">
    </div >
        <div class="content">
            <div class="header">
                <a href="$element.permalink_url" target="_blank">$element.title</a>
            </div>
        </div>
</div >`;
    
    //here i add the card to DOM
    let searchResults = document.querySelector('.js-search-results');
    searchResults.innerHTML += card;

    // store the content of the button 
    let inBtn = `<i class="add icon"></i>
    <span>Add to playlist</span>`;
 
    // created button container 
    let btn = document.createElement("div");
    btn.classList.add("ui", "bottom", "attached", "button", "js-button", "fresh");

    // added the content of the button 
    btn.innerHTML += inBtn;
    

    //here i add the button to the last card have been created
    searchResults.querySelector(".card:last-child").append(btn);
    );
    for (let btn of document.querySelectorAll('.ui.attached.button.js-button.fresh')) 
        // here i add the the event Listener to the button 
        btn.addEventListener('click', () => 
            console.log("click");
        );
    

小提琴:https://jsfiddle.net/r84um9pt/

【讨论】:

【参考方案3】:

我认为: 你在做什么:

let searchResults = document.querySelector('.js-search-results');
searchResults.innerHTML += card;

在您的 div "searchResults" 中一次又一次地序列化

innerHTML ~erases~ 听众,可能它正在~erasing~ 你以前的听众。此外,我不记得我在哪里读到 innerHTML 脚本代码无法运行(出于安全目的)

来自https://medium.com/@kevinchi118/innerhtml-vs-createelement-appendchild-3da39275a694

使用 innerHTML 重新解析并重新创建 div 内的所有 DOM 节点 元素并且效率低于简单地将新元素附加到 分区。在上述情况下,createElement 性能更高 选择。

小心:

一次又一次地使用“追加”会严重使用浏览器资源,重绘多次。 但是,您可以附加一个 documentFragment 并将其附加到 div -js-search-results

文档片段: https://developer.mozilla.org/es/docs/Web/API/DocumentFragment

【讨论】:

【参考方案4】:

欢迎加入社区。在您的代码中,您正在向按钮添加许多类。您可以将事件侦听器添加到仅专门应用于按钮元素的任何唯一类名称中。

你可以替换:

btn.addEventListener('click', () => 
    console.log('click');
);

与:

document.querySelectorAll('.js-button').forEach(el=>
  el.addEventListener('click', (event) => 
  event.preventDefault();
  console.log("click");
 );
);

另外,如果您在添加元素的循环之外添加 eventListener 会很好。

【讨论】:

这将继续添加事件监听器,甚至是已经有监听器的按钮,导致每个按钮触发多次 @Emre 谢谢提醒。我修改了我的答案并添加了event.preventDefault 以避免多个事件触发。 不是我的意思。当tracksRender() 函数被触发时,document.querySelectors('.js-button').addEventListener() 将为所有按钮添加一个事件监听器,对吗?但是下次再次触发时,所有按钮都会再次添加事件侦听器。因此,当您单击任何按钮时,它将记录两次。如果第三次触发tracksRender(),所有按钮将获得另一个侦听器并记录三次,依此类推。最好为每个按钮添加一次侦听器,而不是一次添加到所有按钮。 @LilFlower 这种方法会使复杂性 On²,我正在努力使代码尽可能简单,谢谢。

以上是关于将EventListener 添加到innerHTML的主要内容,如果未能解决你的问题,请参考以下文章

尝试将 EventListener 添加到动态创建的对象

如何将 Javascript eventListener 添加到浏览器生成密码的密码字段?

Javascript Mouseup / Touchend eventListener变量未定义

添加 eventListener 以模糊自定义组件上的事件?

.on mouseover和eventListener正确放置

是否可以为 $builder symfony 中使用 EventListener symfony 添加的字段分配值?