- Первая задача состояла в том, чтобы запустить код.
- Вторая задача - дать подробное объяснение того, что на самом деле происходит и почему вообще не нужен подход, который работает с JavaScript
class
.
class ListItems{
constructor(listItemQuery) {
const listItems = this;
listItemQuery.forEach((listItem) => {
listItem.addEventListener('click', listItems.clickGreen, false);
listItem.addEventListener('onmousedown', listItems.noSelectText, false);
});
}
noSelectText(evt) {
evt.preventDefault;
return false;
}
clickGreen(evt) {
const listItem = evt.currentTarget;
if (evt.ctrlKey || evt.metaKey) {
listItem.classList.add('selected');
return;
}
const firstLevelListItems = Array.from(listItem.parentNode.children);
firstLevelListItems.forEach(function(item) {
item.classList.remove('selected');
});
listItem.classList.add('selected');
}
}
function initializeListItems() {
new ListItems(document.querySelectorAll('li'));
}
window.addEventListener('load', initializeListItems, false);
.as-console-wrapper { max-height: 100%!important; top: 0; }
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
.selected {
background: #0f0;
}
li {
cursor: pointer;
}
</style>
</head>
<body>
Кликни на элемент списка, чтобы выделить его.
<br/>
<ul id="ul">
<li>Кристофер Робин</li>
<li>Винни Пух</li>
<li>Тигра</li>
<li>Кенга</li>
<li>Кролик. Просто Кролик.</li>
</ul>
</body>
</html>
Теперь исполняемый код был разбит на части для лучшей идентификации различных частей предоставленного примера OP.
Если один использует классы JS, всегда лучше, чтобы конструктор отвечал только за самую необходимую часть начальной загрузки. Таким образом, у нас есть шаг инициализации, который передает запрос DOM непосредственно конструктору.
Далее, присвоение имени классу List
вводит в заблуждение, поскольку OP использует его главным образом в качестве структурирующего элемента, который содержит функциональные возможности, которые исключительно управляют элементы списка. Давайте теперь переименуем его в ListItems
.
Каждый HTMLLIElement
затем добавит к нему два собственных обработчика событий. В примере кода OP это дважды функция стрелки, каждый из которых принимает event
аргумент , но не передает его методу предполагаемого класса.
Код может были исправлены так ...
list.addEventListener('click', (event) => this.click_green(event));
list.addEventListener('onmousedown', (event) => this.no_select_text(event));
... но более интуитивно понятным способом было назначение методов класса непосредственно как обработчики событий, например ...
listItem.addEventListener('click', this.clickGreen, false);
listItem.addEventListener('onmousedown', this.noSelectText, false);
После этого далеко не начинают бороться с подходом class
из-за контекста this
метода.
this
в пределах click_green(event) { ... this.classList.add('selected') ... }
не является HTMLLIElement
, но this
всегда является единственным случаем Класс OP List
, созданный во время загрузки.
Объект evt
, как в примере с фиксированным кодом, предоставляет объекты target
и currentTarget
. С заданной HTML -структурой оба содержат ссылку на элемент списка, на который, например, щелкнули. Как только элемент списка больше не просто содержит текстовые узлы, но и является родительским для других HTML элементов, которые могут быть целевыми объектами, инициирующими события, evt.currentTarget
является единственным источником истины из-за обоих добавленных обработчиков событий.
Теперь, будучи уверенным в отношении элемента списка, по которому щелкнули, не нужно просто запрашивать все элементы списка родительского списка, поскольку элементы списка могут быть контейнерами для других списков и так далее. Вместо этого один хочет получить всех братьев и сестер элемента списка. Ориентируясь на них через parentNode
, следует помнить, что parentNode.childNodes
перечисляет любой узел, включая текстовые узлы, которые, например, происходят из новых строк предоставленного примера кода. Каждый всегда находится на стороне сохранения с parentNode.children
, который является HTMLCollection
, который просто перечисляет узлы элемента. Преобразование такой коллекции в массив ... Array.from(listItem.parentNode.children);
... необходимо для обработки ее элементов с помощью методов массива.
Больше нечего сказать о том, как заставить код OP работать так, как мог бы было задумано.
И, надеясь получить лучшее понимание кода, можно даже избавиться от синтаксиса class
, заменив его другим подходом к структурированию кода ...
// list item module
//
// - written as immediately invoked function expression ...
// - ... mainly for encapsulation of domain specific code.
//
const ListItems = (function () {
function preventSelection(evt) {
evt.preventDefault;
return false;
}
function selectItem(evt) {
const listItem = evt.currentTarget;
if (evt.ctrlKey || evt.metaKey) {
listItem.classList.add('selected');
} else {
const firstLevelListItems = Array.from(listItem.parentNode.children);
firstLevelListItems.forEach((item) => {
item.classList.remove('selected');
});
listItem.classList.add('selected');
}
}
function initializeListItems() {
document.querySelectorAll('li').forEach((listItem) => {
listItem.addEventListener('click', selectItem, false);
listItem.addEventListener('onmousedown', preventSelection, false);
})
}
// the module:
return {
initialize: initializeListItems
};
}());
// another task ...
window.addEventListener('load', ListItems.initialize, false);
.as-console-wrapper { max-height: 100%!important; top: 0; }
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
.selected {
background: #0f0;
}
li {
cursor: pointer;
}
</style>
</head>
<body>
Кликни на элемент списка, чтобы выделить его.
<br/>
<ul id="ul">
<li>Кристофер Робин</li>
<li>Винни Пух</li>
<li>Тигра</li>
<li>Кенга</li>
<li>Кролик. Просто Кролик.</li>
</ul>
</body>
</html>