简体   繁体   English

为快照 Firestore 中的每个元素添加事件侦听器

[英]Add event listener for each element in snapshot Firestore

I have the following code that gets a snapshot from my Firestore collection called banner .我有以下代码从名为banner Firestore 集合中获取snapshot Each object has the following structure每个对象具有以下结构

{
   index: // each object has index
   image: // url of source image
   link: // link to be redirected when clicked the image
}

Here is the HTML code where I dynamically add elements to HTML from my collection, I have 5 images in this case这是我从我的集合动态添加元素到 HTML 的 HTML 代码,在这种情况下我有5图像

<div id="homepage-background" class="background">
      <img class="bg" src="https://firebasestorage.googleapis.com/v0/b....">
      <img class="bg" src="https://firebasestorage.googleapis.com/v0/b....">
      <img class="bg" src="https://firebasestorage.googleapis.com/v0/b....">
      <img class="bg" src="https://firebasestorage.googleapis.com/v0/b....">
      <img class="bg" src="https://firebasestorage.googleapis.com/v0/b....">
</div>

And here is the function这是功能

    let homepageBackground = document.getElementById("homepage-background");

    firebase
      .firestore()
      .collection("banner")
      .orderBy("index")
      .get()
      .then((snapshot) => {
        let array = snapshot.docs;

        for (let i = 0; i < array.length; i++) {
            console.log(array[i].data());
            console.log("i before " + i);

            let imgBackground = document.createElement("img");
            imgBackground.setAttribute("class", "bg");
            imgBackground.setAttribute("src", array[i].image);
            imgBackground.setAttribute("data-index", i);
            console.log("i after " + i);
  
            imgBackground.addEventListener("click", function () {
              const alertText = imgBackground.getAttribute("data-index");
              alert(alertText);
            });
            homepageBackground.appendChild(imgBackground);
        }
      })
      .catch((error) => {
        console.log(error);
      });

The problem is the each image I click, it alerts 5 , the index of the last element in my collection.问题是我点击的每张图片,它都会提醒5 ,这是我收藏中最后一个元素的索引。 I expect that when I click on the first picture to get an alert with 1 , click on second picture, get an alert of 2 and so on until the fifth picture to get an alert of 5 .我希望,当我在第一个点击图片以得到一个警报1 ,点击第二张照片,得到一个警报2 ,以此类推,直到第五图片获得的警报5 Somehow that index attribute of each document from collection is not displayed correctly since no matter picture I click, I get an alert of 5 , index of the last element.不知何故,集合中每个文档的index属性没有正确显示,因为无论我点击图片,我都会收到5的警报,即最后一个元素的索引。 I believe the problem is with addEventListener() function that might have been assigned only to the last HTML element because it always displays 5 .我认为问题在于addEventListener()函数可能只分配给最后一个 HTML 元素,因为它总是显示5

I am not quite sure why is it not working and what should I do to fix.我不太确定为什么它不起作用,我应该怎么做才能解决。

EDIT编辑

I have added 2 console logs, before and after imgBackground.setAttribute("data-index", i);我在imgBackground.setAttribute("data-index", i);之前和之后添加了 2 个控制台日志imgBackground.setAttribute("data-index", i);

and it displays the following once the page is loaded一旦页面加载,它会显示以下内容

i before 0
i after 0
i before 1
i after 1
i before 2
i after 2
i before 3
i after 3
i before 4
i after 4

My assumption is that all images are already rendered to the HTML since they are displayed correctly to the screen.我的假设是所有图像都已呈现为 HTML,因为它们已正确显示在屏幕上。 But only that after the loop i was set last index.但只有在循环之后i才被设置为最后一个索引。 I have to mention that I have one more script file that is responsible for sliding the images in the page.不得不提的是,我还有一个脚本文件负责在页面中滑动图像。 It is just a setInterval() that runs every 5 seconds and adds show class to each img from that div .它只是一个每 5 秒运行一次的setInterval()并将show类添加到该div每个img The following is the script.以下是脚本。

  document.addEventListener(
    "load",
    function () {
      let slider = document.querySelector(".slider");
      let buttons = document.querySelectorAll(".btn");
      let slides = document.querySelectorAll(".img");
      let backgrounds = document.querySelectorAll(".bg");
      let options = document.querySelectorAll(".option");

      let element = document.getElementById("homepage-background");
      let numberOfChildren = element.getElementsByTagName("img").length;

      let index = 1;
      let op_index = 0;

      let size = slides[index].clientWidth;

      update();

      function update() {
        slider.style.transform = "translateX(" + -size * index + "px)";

        backgrounds.forEach((img) => img.classList.remove("show"));
        backgrounds[op_index].classList.add("show");

        options.forEach((op) => op.classList.remove("colored"));
        options[op_index].classList.add("colored");
      }

      function slide() {
        slider.style.transition = "transform .5s ease-in-out";
        update();
      }

      function btnCheck() {
        if (this.id === "prev") {
          index--;

          if (op_index === 0) {
            op_index = numberOfChildren - 1;
          } else {
            op_index--;
          }
        } else {
          index++;

          if (op_index === numberOfChildren - 1) {
            op_index = 0;
          } else {
            op_index++;
          }
        }
        slide();
      }

      slider.addEventListener("transitionend", () => {
        if (index >= numberOfChildren - 1) {
          return;
        }
        if (index <= 0) {
          return;
        }
        if (slides[index].id === "fist") {
          slider.style.transition = "none";
          index = slides.length - 2;
          slider.style.transform = "translateX(" + -size * index + "px)";
        } else if (slides[index].id === "last") {
          slider.style.transition = "none";
          index = 1;
          slider.style.transform = "translateX(" + -size * index + "px)";
        }
      });

      buttons.forEach((btn) => btn.addEventListener("click", btnCheck));
      options.forEach((option) => option.addEventListener("click", optionFunc));

      setInterval(btnCheck, 5000);
    },
    5000
  );

By the time the page renders, the loop has terminated and i == 5 , which is why your test alert always shows 5.到页面呈现时,循环已终止并且i == 5 ,这就是为什么您的测试警报始终显示 5。

I agree with @Marc that you should associate the element with its index and store it somewhere inside the loop.我同意@Marc 的观点,即您应该将元素与其索引相关联并将其存储在循环内的某个位置。

modified from here :这里修改:

...
for (let i = 0; i < array.length; i++) {
  ...
  // SET attribute "data-index"
  imgBackground.setAttribute("data-index", i) // or array[i].data().index, which appears to be the same thing based on your description
  
  imgBackground.addEventListener("click", function () {
    // GET attribute "data-index"
    const alertText = imgBackground.getAttribute('data-index')
    alert(alertText);
    ...
  });
  ...
}
...

Tested in developer console and working.在开发人员控制台中测试并正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM