Добавьте классы уровней во вложенный список с помощью Javascript Vanilla - PullRequest
1 голос
/ 15 апреля 2020

Я пытаюсь добавить предложения уровня в список с вложенными элементами списка. Мне нужна следующая структура.

<ul class="parent parent-level-1">
  <li class="child child-level-1"><a>Title level 1</a></li>
  <li class="child child-level-1"><a>Title level 1</a>
    <ul class="parent parent-level-2">
      <li class="child child-level-2"><a>Title level 2</a>
        <ul class="parent parent-level-3">
          <li class="child child-level-3"><a>Title level 3</a></li>
          <li class="child child-level-3"><a>Title level 3</a></li>
        </ul>
      </li>
      <li class="child child-level-2"><a>Title level 2</a>
        <ul class="parent parent-level-3">
          <li class="child child-level-3"><a>Title level 3</a></li>
          <li class="child child-level-3"><a>Title level 3</a></li>
          <li class="child child-level-3"><a>Title level 3</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="child child-level-1"><a>Title level 1</a>
    <ul class="parent parent-level-2">
      <li class="child child-level-2"><a>Title level 2</a></li>
    </ul>
  </li>
  <li class="child child-level-1"><a>Title level 1</a></li>
  <li class="child child-level-1"><a>Title level 1</a>
    <ul class="parent parent-level-2">
      <li class="child child-level-2"><a>Title level 2</a></li>
    </ul>
  </li>
</ul>

Как видите, внутри родительского списка есть несколько вложенных списков, которые в то же время могут содержать другие вложенные списки. Я попробовал следующую функцию Javascript, где parent является родителем основного списка, а level целое число для первого уровня, может быть 0 или 1.

function addLevelClass(parent, level) {
  const iteration = parent.querySelectorAll("ul");

  const firstUL = parent.querySelector("ul");
  firstUL.classList.add("parent", "parent-level-" + level);

  const firstItems = parent.querySelectorAll("li");

  console.info(firstItems);

  // No point if no list items.
  if (!firstItems.length) {
    return;
  }

  //loop trough fisrt-level li
  for (let c = 0; c < firstItems.length; c++) {
    const childrenLi = firstItems[c];

    //add a child class to the li
    childrenLi.classList.add("child", "child-level-" + level);
  }

  // No point if no list items.
  if (!iteration.length) {
    return;
  }
  for (let g = 0; g < iteration.length; g++) {
    const levelIncrement = level + g;

    const parentUL = iteration[g].querySelector("ul");

    //add a parent class to the ul
    parentUL.classList.add(
      "parent",
      "parent-level-" + (level + levelIncrement)
    );

    //fetch all the li's that are direct children of the ul
    const childItems = parentUL.querySelectorAll("li");

    // No point if no list items.
    if (!childItems.length) {
      return;
    }

    //loop trough each li
    for (let c = 0; c < childItems.length; c++) {
      const childrenLi = childItems[c];

      //add a child class to the li
      childrenLi.classList.add(
        "child",
        "child-level-" + (level + levelIncrement)
      );
    }
  }
}

Функция теряется где-то на уровне 3er и не устанавливает уровни для остальной части списка.

1 Ответ

0 голосов
/ 15 апреля 2020

Лучший способ понять эту проблему состоит в том, что структура HTML - это структура данных Tree (на самом деле это DAG, если вы хотите sh продолжить исследование).

Эти проблемы являются частью структуры данных CS101 (и как пройти / поиск). Предоставлено решение DFS.

Однако для решения этой проблемы необходимо учитывать recursion.

т.е. с учетом древовидной структуры следующего

| root
|
|- leaf node
|- node with children
 |- leaf node

Итак, идея в том, где вы сначала найдете узел root. Здесь вы ищете document.querySelector('ul')

, затем вы будете искать листовые узлы в root ul. здесь вы будете делать что-то вроде document.querySelector('ul > li'). это даст вам существующие дочерние узлы от root.

оттуда - вам нужно будет переключить родительский элемент с дочерним, чтобы выполнить действие рекурсивно.

я предоставлю пример ниже:

// helper fn
const findChildren = el => [...el.children].filter(el => el.tagName === "LI")

const root = document.querySelector("ul");
const children = findChildren(root);


const traverse = (baseNode, children, iter = 1) => {
  // process baseNode here with iter here
  baseNode.classList.add(`list-${iter.toString()}`)

  for (child of children) {
     child.classList.add(`child-${iter.toString()}`)
     let hasGranChild = [...child.children].filter(el => el.tagName === "UL").length

     if (hasGranChild) {
       let newChild = [...child.children].find(el => el.tagName === "UL");
       const granChildren = findChildren(newChild)

       traverse(newChild, granChildren, iter + 1)
     }
  }
}

traverse(root, children)
<ul>
  <li><a>Title level 1</a></li>
  <li><a>Title level 1</a>
    <ul>
      <li><a>Title level 2</a>
        <ul>
          <li><a>Title level 3</a></li>
          <li><a>Title level 3</a></li>
        </ul>
      </li>
      <li><a>Title level 2</a>
        <ul>
          <li><a>Title level 3</a></li>
          <li><a>Title level 3</a></li>
          <li><a>Title level 3</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a>Title level 1</a>
    <ul>
      <li><a>Title level 2</a></li>
    </ul>
  </li>
  <li><a>Title level 1</a></li>
  <li><a>Title level 1</a>
    <ul>
      <li><a>Title level 2</a></li>
    </ul>
  </li>
</ul>

Результат

<ul class="list-1">
  <li class="child-1"><a>Title level 1</a></li>
  <li class="child-1"><a>Title level 1</a>
    <ul class="list-2">
      <li class="child-2"><a>Title level 2</a>
        <ul class="list-3">
          <li class="child-3"><a>Title level 3</a></li>
          <li class="child-3"><a>Title level 3</a></li>
        </ul>
      </li>
      <li class="child-2"><a>Title level 2</a>
        <ul class="list-3">
          <li class="child-3"><a>Title level 3</a></li>
          <li class="child-3"><a>Title level 3</a></li>
          <li class="child-3"><a>Title level 3</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="child-1"><a>Title level 1</a>
    <ul class="list-2">
      <li class="child-2"><a>Title level 2</a></li>
    </ul>
  </li>
  <li class="child-1"><a>Title level 1</a></li>
  <li class="child-1"><a>Title level 1</a>
    <ul class="list-2">
      <li class="child-2"><a>Title level 2</a></li>
    </ul>
  </li>
</ul>

в рамках рекурсивного характера функции вы можете перейти на текущий «уровень» "внутри аргументов функции. Задав начальный iter = 1, вам все равно, насколько "глубоко" уходит дерево. И так как вы используете CSS селектор прямого потомка (то есть el1 > el2), который вы спрашиваете, можете ли вы дать мне прямых потомков el1 which are el2?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...