Обновление коллекции из HTML элементов в цикле forEach - PullRequest
1 голос
/ 06 августа 2020

Я пытаюсь обновить коллекцию HTML элементов внутри forEach l oop. Поскольку до раздела 3 кажется, что все работает, но всякий раз, когда я пытаюсь добавить новый раздел, возникает проблема, и кнопки на панели навигации не работают с раздела 4 и выше.

Вот мой HTML:

    <main id="main">
      <header class="main__hero">
        <nav>
          <ul class="flex-container">
            <li>Section 1</li>
            <li>Section 2</li>
            <li>Section 3</li>
            <li id="new-section">NEW SECTION</li>
            <li id="back">BACK TO TOP</li>
          </ul>
        </nav>
        <h1>Landing Page</h1>
      </header>
      <section id="section1" data-nav="Section 1" class="your-active-class">
        <div class="landing__container">
          <h2>Section 1</h2>
          <p>
          </p>
          <p>
          </p>
        </div>
      </section>
      <section id="section2" data-nav="Section 2">
        <div class="landing__container">
          <h2>Section 2</h2>
          <p>
          </p>
          <p>
          </p>
        </div>
      </section>
      <section id="section3" data-nav="Section 3">
        <div class="landing__container">
          <h2>Section 3</h2>
          <p>
          </p>
          <p>
          </p>
        </div>
      </section>
    </main>

Вот мой JavaScript:

let allSections = document.querySelectorAll("section");
let allLists = document.querySelectorAll("li");
let n = 4;

// This function runs wherever the user press add new section button.
function duplicate(num) {
  const newSection = document.createElement("section");
  const newDiv = document.createElement("div");
  const heading = document.createElement("h2");
  const p1 = document.createElement("p");
  const p2 = document.createElement("p");

  newSection.appendChild(newDiv);
  newDiv.appendChild(heading);
  newDiv.appendChild(p1);
  newDiv.appendChild(p2);

  newSection.setAttribute("id", "section" + num);
  newSection.setAttribute("data-nav", "Section" + " " + num);
  newDiv.setAttribute("class", "landing__container");

  heading.textContent = "Section" + " " + num;
  p1.textContent =
    "New text";
  p2.textContent =
    "New text";
  return newSection;
}
// Append the above function to the body.
newSectionBtn.addEventListener("click", () => {
  newSectionBtn.insertAdjacentHTML("beforebegin", "<li> Section" + " " + n + "</li>");
  main.appendChild(duplicate(n));
  main.lastElementChild.scrollIntoView({ behavior: "smooth" });
  n++;
});

// The problem start here...
allLists.forEach((list, index) => {
  list.addEventListener("click", () => {
    allSections[index].scrollIntoView({ behavior: "smooth" });
    allSections = document.querySelectorAll("section");
    allLists = document.querySelectorAll("li");
    //console.log("clicked");
  });
});

ОБНОВЛЕНИЕ: Проблема решена, когда я помещаю foreach l oop внутрь:

window.addEventListener("scroll", () => {
  allLists.forEach((list, index) => {
    list.addEventListener("click", () => {
      allSections[index].scrollIntoView({ behavior: "smooth" });
      allSections = document.querySelectorAll("section");
      allLists = document.querySelectorAll("li");
    });
  });
});

Но в консоли есть странная ошибка рассылки спама

Uncaught TypeError: Cannot read property 'scrollIntoView' of undefined
    at HTMLLIElement.<anonymous>

Есть идеи, как это исправить?

Ответы [ 3 ]

0 голосов
/ 06 августа 2020

Проблема в этой строке:

allSections[index].scrollIntoView({ behavior: "smooth" });

Поскольку вы используете индекс allLists (LI) для доступа к allSections (section), вам нужно иметь такое же количество разделов и li.

Я бы порекомендовал добавить класс ignore к следующим LI элементам:

<li class="ignore" id="new-section">NEW SECTION</li>
<li class="ignore" id="back">BACK TO TOP</li>

Если у вас такое же количество элементов SECTION, как и у вас есть элементы LI (исключая 2 проигнорированных элемента), тогда вы не должны получать ошибку.

Обновление : Я исправил следующую строку (раньше был знак #). Убедитесь, что оба назначения allLists обновлены:

allLists = document.querySelectorAll("li:not(.ignore)");

Примечание : поскольку allLists l oop теперь находится в событии scroll, он не получит инициализируется до тех пор, пока пользователь не прокрутится.

var newSectionBtn = document.getElementById("newSectionBtn");
let allSections = document.querySelectorAll("section");
let allLists = document.querySelectorAll("li:not(.ignore)");
let n = 4;

// This function runs wherever the user press add new section button.
function duplicate(num) {
    const newSection = document.createElement("section");
    const newDiv = document.createElement("div");
    const heading = document.createElement("h2");
    const p1 = document.createElement("p");
    const p2 = document.createElement("p");

    newSection.appendChild(newDiv);
    newDiv.appendChild(heading);
    newDiv.appendChild(p1);
    newDiv.appendChild(p2);

    newSection.setAttribute("id", "section" + num);
    newSection.setAttribute("data-nav", "Section" + " " + num);
    newDiv.setAttribute("class", "landing__container");

    heading.textContent = "Section" + " " + num;
    p1.textContent =
        "New text";
    p2.textContent =
        "New text";
    return newSection;
}
// Append the above function to the body.
newSectionBtn.addEventListener("click", () => {
    newSectionBtn.insertAdjacentHTML("beforebegin", "<li> Section" + " " + n + "</li>");
    main.appendChild(duplicate(n));
    main.lastElementChild.scrollIntoView({ behavior: "smooth" });
    n++;
});

window.addEventListener("scroll", () => {
    allLists.forEach((list, index) => {
        list.addEventListener("click", () => {
            allSections[index].scrollIntoView({ behavior: "smooth" });
            allSections = document.querySelectorAll("section");
            allLists = document.querySelectorAll("li:not(.ignore)");
        });
    });
});
<button id="newSectionBtn">Hello</button>
<main id="main">
    <header class="main__hero">
        <nav>
            <ul class="flex-container">
                <li>Section 1</li>
                <li>Section 2</li>
                <li>Section 3</li>
                <li class="ignore" id="new-section">NEW SECTION</li>
                <li class="ignore" id="back">BACK TO TOP</li>
            </ul>
        </nav>
        <h1>Landing Page</h1>
    </header>
    <section id="section1" data-nav="Section 1" class="your-active-class">
        <div class="landing__container">
            <h2>Section 1</h2>
            <p>
            </p>
            <p>
            </p>
        </div>
    </section>
    <section id="section2" data-nav="Section 2">
        <div class="landing__container">
            <h2>Section 2</h2>
            <p>
            </p>
            <p>
            </p>
        </div>
    </section>
    <section id="section3" data-nav="Section 3">
        <div class="landing__container">
            <h2>Section 3</h2>
            <p>
            </p>
            <p>
            </p>
        </div>
    </section>
</main>
0 голосов
/ 06 августа 2020

Чтобы использовать forEach в коллекции HTML, вам нужно распределить его в массив:

let allLists = [...document.querySelectorAll("li")];
0 голосов
/ 06 августа 2020

Я считаю, что всякий раз, когда вы добавляете новый раздел, вы также должны подключать событие click. Блок forEach запускается только один раз при загрузке скрипта и, таким образом, «знает» только первые 3 элемента списка разделов.

...