点击事件监听器多次触发

时间:2020-08-06 17:14:51

标签: javascript

我有一个嵌套的<i>标签,显示喜欢的或不同的心脏。问题在于,每当喜欢某个帖子时,它就会发送大约16个请求(事件触发16次)。我尝试使用sleepseTimeout无济于事。我需要将事件侦听器动态添加到<i>标记中。

initial_html

{% if user in post.get_likers%}
        <p class="my-0 text-muted"><i style="color: red;" class="fas fa-heart hover"></i> {{post.total_likes}}</p>
{% else %}
        <p class="my-0 text-muted"><i class="far fa-heart hover"></i> {{post.total_likes}}</p>
{% endif %}

尝试按观看次数更新点赞

document.addEventListener("DOMContentLoaded", () => {
  load_clickable();
});

function load_clickable() {
  document.querySelectorAll("i").forEach((item) => {
    item.addEventListener("click", () => {
      update_likes(item);
    });
  });
}

function update_likes(item) {
  const p_tag = item.parentNode;
  const post_id = p_tag.parentNode.id;
  console.log(post_id, p_tag.innerText);
  const fetch_url = `/like/${post_id}`;
  fetch(fetch_url, {
    method: "POST",
  })
    .then((response) => response.json())
    .then((result) => {
      if (result.like) {
        console.log("Has Liked");
        var new_likes = parseInt(p_tag.innerText) + 1;
        p_tag.innerHTML = `<i style="color: red;" class="fas fa-heart hover"></i> ${new_likes}`;
      } else if (result.unlike) {
        console.log("Has unliked");
        var new_likes = parseInt(p_tag.innerText) - 1;
        p_tag.innerHTML = `<i class="far fa-heart hover"></i> ${new_likes}`;
      }
      load_clickable();
    });
}

如何使每个事件触发一次?

2 个答案:

答案 0 :(得分:2)

问题在于,您在更新点赞后正在调用load_clickable,这会将事件侦听器再次添加到所有<i>元素中。相反,您应该在<span>中显示喜欢的数量,并每次更新textContent,这样就不必再次附加所有事件侦听器。

更新的HTML:

{% if user in post.get_likers%}
        <p class="my-0 text-muted"><i style="color: red;" class="fas fa-heart hover"></i> <span>{{post.total_likes}}</span></p>
{% else %}
        <p class="my-0 text-muted"><i class="far fa-heart hover"></i> <span>{{post.total_likes}}</span></p>
{% endif %}

更新的JavaScript(为简洁起见,省略了部分内容):

//...
.then((result) => {
      if (result.like) {
        console.log("Has Liked");
        var new_likes = parseInt(p_tag.innerText) + 1;
        p_tag.querySelector('span').textContent = new_likes;
      } else if (result.unlike) {
        console.log("Has unliked");
        var new_likes = parseInt(p_tag.innerText) - 1;
        p_tag.querySelector('span').textContent = new_likes;
      }
    });
//...

答案 1 :(得分:1)

问题是调用load_clickable方法,单击事件在技术上仍然处于活动状态,为什么不将onclick attr加载到新的i标签,就像这样

.then((result) => {
      if (result.like) {
        console.log("Has Liked");
        var new_likes = parseInt(p_tag.innerText) + 1;
        p_tag.innerHTML = `<i style="color: red;" class="fas fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
      } else if (result.unlike) {
        console.log("Has unliked");
        var new_likes = parseInt(p_tag.innerText) - 1;
        p_tag.innerHTML = `<i class="far fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
      }
    });

最佳解决方案

{% if user in post.get_likers%}
        <p class="my-0 text-muted"><i style="color: red;" class="fas fa-heart hover onclick=update_likes()"></i> <span>{{post.total_likes}}</span></p>
{% else %}
        <p class="my-0 text-muted"><i class="far fa-heart hover onclick=update_likes()"></i> <span>{{post.total_likes}}</span></p>
{% endif %}

然后是javascript

document.addEventListener("DOMContentLoaded", () => {
    //do something else with loaded DOM
});

function update_likes() {
  const p_tag = this.parentNode;
  const post_id = p_tag.parentNode.id;
  console.log(post_id, p_tag.innerText);
  const fetch_url = `/like/${post_id}`;
  fetch(fetch_url, {
    method: "POST",
  })
    .then((response) => response.json())
    .then((result) => {
      if (result.like) {
        console.log("Has Liked");
        var new_likes = parseInt(p_tag.innerText) + 1;
        p_tag.innerHTML = `<i style="color: red;" class="fas fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
      } else if (result.unlike) {
        console.log("Has unliked");
        var new_likes = parseInt(p_tag.innerText) - 1;
        p_tag.innerHTML = `<i class="far fa-heart hover" onclick=update_likes(this)></i> ${new_likes}`;
      }
    });
}

这样,所有标签都已经带有其标签呈现