6.5. Демонстрация - Красим списки

Шаг 1

Перед тем, как перейти непосредственно к окраске, немного подготовимся: возьмём ноду с корнем списка из DOM и перенесём список цветов.


const root = document.getElementById('root');
const colors = ['#DCD6F7', '#A6B1E1', '#B4869F'];

Шаг 2

Для начала напишем обычный обход дерева в ширину и попробуем окрасить список в случайные цвета, чтобы убедиться, что все ноды действительно обходятся. Теперь список выглядит слишком пёстро и несуразно, возможно, из технологов плохие дизайнеры...


const root = document.getElementById('root');
const colors = ['#DCD6F7', '#A6B1E1', '#B4869F'];

function color(node) {
  // та же очередь для просмотра нод
  const queue = [];

  queue.push(node);

  // обходим все ноды из списка
  while(queue.length) {
    // получаем ноду из списка
    const currentNode = queue.shift();

    // красим её
    const randomColorIndex = Math.floor(Math.random() * colors.length);
    currentNode.style.backgroundColor = colors[randomColorIndex];

    // и кладем в очередь всех потомков
    queue.push(...currentNode.children);
  }
}

color(root);

Шаг 3

Нетрудно заметить, что мы красим не только li, как нам надо по условию задания, но и вообще все элементы! Исправим это.


const root = document.getElementById('root');
const colors = ['#DCD6F7', '#A6B1E1', '#B4869F'];
const elementToStyle = 'LI';

function color(node) {
  // та же очередь для просмотра нод
  const queue = [];

  queue.push(node);

  // обходим все ноды из списка
  while(queue.length) {
    // получаем ноду из списка
    const currentNode = queue.shift();

    // если это нода, которую нам нужно красить ...
    if (currentNode.tagName === elementToStyle) {
      // ... красим её
      const randomColorIndex = Math.floor(Math.random() * colors.length);
      currentNode.style.backgroundColor = colors[randomColorIndex];
    }

    // и кладем в очередь всех потомков
    queue.push(...currentNode.children);
  }
}

color(root);

Шаг 4

А теперь надо как-то понять, на каком уровне вложенности мы находимся. Самый простой способ это сделать — просто присвоить эту информацию прямо в элемент очереди! Тогда во время добавления новых элементов в очередь, если мы дошли до новой вложенности (встретили li), будем ставить им вложенность в текущая + 1.


const root = document.getElementById('root');
const colors = ['#DCD6F7', '#A6B1E1', '#B4869F'];
const elementToStyle = 'LI';

function color(node) {
  // та же очередь для просмотра нод
  const queue = [];

  queue.push({
    node,
    depth: 0,
  });

  // обходим все ноды из списка
  while(queue.length) {
    // получаем ноду из списка
    const {node: currentNode, depth: currentDepth} = queue.shift();
    const isStylable = currentNode.tagName === elementToStyle

    // если это нода, которую нам нужно красить ...
    if (isStylable) {
      // ... красим её
      const randomColorIndex = Math.floor(Math.random() * colors.length);
      currentNode.style.backgroundColor = colors[randomColorIndex];
    }


    // и кладем в очередь всех потомков с обновленной глубиной
    for (const node of currentNode.children) {
      queue.push({
        node,
        depth: isStylable ? currentDepth + 1 : currentDepth,
      })
    }
  }
}

color(root);

Шаг 5

Теперь осталось только красить в цвет подстать глубине.


const root = document.getElementById('root');
const colors = ['#DCD6F7', '#A6B1E1', '#B4869F'];
const elementToStyle = 'LI';

function color(node) {
  // та же очередь для просмотра нод
  const queue = [];

  queue.push({
    node,
    depth: 0,
  });

  // обходим все ноды из списка
  while(queue.length) {
    // получаем ноду из списка
    const {node: currentNode, depth: currentDepth} = queue.shift();
    const isStylable = currentNode.tagName === elementToStyle

    // если это нода, которую нам нужно красить ...
    if (isStylable) {
      // ... красим её
      currentNode.style.backgroundColor = colors[currentDepth];
    }


    // и кладем в очередь всех потомков с обновленной глубиной
    for (const node of currentNode.children) {
      queue.push({
        node,
        depth: isStylable ? currentDepth + 1 : currentDepth,
      })
    }
  }
}

color(root);

Шаг 6

И конечно, не забыть обработать случай вложенности больше трёх!


const root = document.getElementById('root');
const colors = ['#DCD6F7', '#A6B1E1', '#B4869F'];
const elementToStyle = 'LI';

function color(node) {
  // та же очередь для просмотра нод
  const queue = [];

  queue.push({
    node,
    depth: 0,
  });

  // обходим все ноды из списка
  while(queue.length) {
    // получаем ноду из списка
    const {node: currentNode, depth: currentDepth} = queue.shift();
    const isStylable = currentNode.tagName === elementToStyle

    // если это нода, которую нам нужно красить ...
    if (isStylable) {
      // ... красим её
      currentNode.style.backgroundColor = colors[currentDepth % 3];
    }


    // и кладем в очередь всех потомков с обновленной глубиной
    for (const node of currentNode.children) {
      queue.push({
        node,
        depth: isStylable ? currentDepth + 1 : currentDepth,
      })
    }
  }
}

color(root);