Задать вопрос
@julith

Как переключить подсветку на следующий элемент списка при нажатии стрелок вверх-вниз?

Пытаюсь настроить событие которое будет распознавать клик стрелочками вверх-вниз и переключать подсветку с Local Disk (C:) на Disk (D:) и (E:). Как это реализовать? По идее в цикле перебираются li с классом parent, и у того, который должен быть подсвечен добавляется к классу пометка active. А как переключать, если стрелка вверх нажимается?

<div>This PC
    <ul class="list" id="list">
        <li class="parent active">Local Dick(C:)
            <ul>
                <li>Programm Files</li>
                <li>Users</li>
                <li>Windows</li>
            </ul>
        </li>
        <li class="parent">Local Dick(D:)
            <ul>
                <li>New Folder 1</li>
                <li>New Folder 2</li>
                <li>New Folder 3</li>
            </ul>
        </li>
        <li class="parent">Local Dick(E:)
            <ul>
                <li>Games
                    <ul>
                        <li>GTA</li>
                        <li>Assasin's creed</li>
                        <li>Skyrim</li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>    
</div>

for (let li of list.querySelectorAll("li")) {
    let span = document.createElement("span"); //создает пространство для клика
    span.classList.add("show");
    li.prepend(span);
    span.append(span.nextSibling);
}

list.onclick = function (event) {
    if (event.target.tagName != "SPAN") return;

    let childrenList = event.target.parentNode.querySelector("ul");

    if (!childrenList) return;
    childrenList.hidden = !childrenList.hidden;

    if (childrenList.hidden) {
        event.target.classList.add("hide");
        event.target.classList.remove("show");
    } else {
        event.target.classList.add("show");
        event.target.classList.remove("hide");
    }
    
};


//подсветка
const parentLi = list.getElementsByClassName('parent');

for(var i = 0; i < parentLi.length; i++) {
    light(parentLi[i].firstChild)
}

function light(parentLi) {
    parentLi.addEventListener('mouseover', function() {
        this.style.color = 'pink';
        this.style.backgroundColor = 'grey';
    })
    parentLi.addEventListener('mouseout', function() {
        this.style.color = 'black';
        this.style.backgroundColor = 'white';
    })
}

//задание 4
//автоматическое переключение при клике
list.addEventListener('keydown', function(parentLi) {
    for (var i = 0; i < parentLi.length; i++) { 
        light(parentLi[i].firstChild); //подсветка 1го элемента
        if (parentLi[i].classList.contains('active')) {
            parentLi[i].classList.remove('active'); //удаляем пометку для подсветки 1го элемента
        }
    }
    parentLi[i].classList.add('active'); //добавляем пометку для следующего эл-та
});
  • Вопрос задан
  • 218 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Где и какой класс надо переключать:

const container = document.querySelector('#list');
const activeClass = 'active';

Переключаем:

container.firstElementChild.classList.add(activeClass);

document.addEventListener('keydown', e => {
  const nextElKey = ({
    ArrowDown: 0,
    ArrowUp: 1,
  })[e.key];

  const currEl = container.querySelector(`:scope > .${activeClass}`);
  const nextEl =
    currEl[[ 'nextElementSibling', 'previousElementSibling' ][nextElKey]]/* ??
    container[[ 'firstElementChild', 'lastElementChild' ][nextElKey]]*/;

  // если надо, чтобы при переходе от последнего к следующему элементу
  // активным становился первый, а при переходе от первого к предыдущему
  // активным становился последний, достаточно удалить многострочное 
  // комментирование выше

  if (nextEl) {
    currEl.classList.remove(activeClass);
    nextEl.classList.add(activeClass);
  }
});

или

const next = function(step) {
  this[1][this[0]].classList.remove(activeClass);

  this[0] = Math.max(0, Math.min(this[1].length - 1, this[0] + step));
  // или, если надо, чтобы выделение по кругу бегало
  // this[0] = (this[0] + step + this[1].length) % this[1].length;

  this[1][this[0]].classList.add(activeClass);
}.bind([ 0, container.children ]);

next(0);

document.addEventListener('keydown', e => {
  const step =
    e.key === 'ArrowDown' ?  1 :
    e.key === 'ArrowUp'   ? -1 :
                             0;
  if (step) {
    next(step);
  }
});
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
bingo347
@bingo347 Куратор тега JavaScript
Crazy on performance...
Ну для начала, вот сюда:
list.addEventListener('keydown', function(parentLi) {
параметром придет KeyboardEvent, в котором есть данные о нажатых клавишах.

По идее в цикле перебираются li с классом parent, и у того, который должен быть подсвечен добавляется к классу пометка active
Хранить состояние во view слое очень плохая идея. Запоминайте индекс выделенного элемента в переменной и по событию проверяйте возможность переключения подсветки и меняйте классы.

Ну и так, замечание:
for(var i = 0; i < parentLi.length; i++) {
    light(parentLi[i].firstChild)
}

function light(parentLi) {
    parentLi.addEventListener('mouseover', function() {
        this.style.color = 'pink';
        this.style.backgroundColor = 'grey';
    })
    parentLi.addEventListener('mouseout', function() {
        this.style.color = 'black';
        this.style.backgroundColor = 'white';
    })
}
вот тут в цикле создается целая пачка однотипных функций, каждая из которых будет жрать память пользователя. Притом эта задача вообще легко решается на чистом CSS через hover.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы