Веб-разработка
April 12, 2022

Знакомство с JavaScript — Тренажёр HTML Academy

Продолжаем глубже знакомиться с веб-разработкой и по программе тренажёров HTML Academy на очереди у нас идет JavaScript, который уже не вёрстка, а язык программирования.

В позапрошлом блоке мы легонечко уже «знакомились» с JS, там мы искали элементы и меняли им классы с помощью простого обработчика событий, что даже так меня впечатлило как туземца вертолёт.

Я чутка поэкспериментирую со статьями, попробую вернуться к формату «один блок — одна статья», как и было сначала, но постараюсь сократить растекания мыслей по древу.

Часть 1: Условия и создание элементов

В прошлый раз нам надо было найти элемент и поменять ему класс, таким образом поменяв тему сайта, теперь задачка масштабами меньше, но функционально посложнее — нам надо прикрутить лайки!

Лайки

По нажатию на кнопку лайка одновременно происходит несколько событий. Идем от общего к частному — индикатор лайка заполняется, а счетчик количества лайков увеличивается на один.

Для работы нам нужен сам элемент с индикатором, подготовить для него два стиля — пустой (по умолчанию) и заполненный, а также элемент счетчика с одним классом — у него меняется значение, а не состояние.

Находим наши элементы и объявляем переменные:

let heart = document.querySelector('.heart');
let likesNumber = document.querySelector('.likes-number');

С обработчиком событий по клику .onclick мы знакомы и как менять классы classList.toggle мы тоже уже знаем, с индикатором всё понятно. В счетчике меняется число, то бишь контент .textContent, его мы тоже уже знаем.

Что мы пока не знаем — это как увеличить число лайков на один, а не просто поменять на произвольный контент. Это сделать можно несколькими способами:

num = num + 2 // полная запись 
num += 2 // короткая запись
num++ // увеличение на 1 ("+= 1" или "num + 1")

Нам подходят все, но последний как раз придуман умными дядьками для таких задач как наша. Видимо, очень часто надо именно «+1». В итоге получается:

heart.onclick = function () {
  likesNumber.textContent++; // прибавляем лайк
  heart.classList.toggle('added'); // заполняем индикатор
};

Но у нас проблема! Индикатор-то работает в обе стороны, а вот счетчик прибавляет, но не убавляет количество при снятии лайка. Идем, опять же, от общего к частому. Если индикатор пустой — нужно прибавить, если заполнен — убавить. Теперь надо это написать на языке JS.

В этом нам поможет метод classList.contains(), который проверяет наличие класса в указанном элементе и возвращает True или False, то есть «Верно» или «Неверно». С этим методом и условными операторами if (условие) {ф-ция} и else {другая ф-ция} мы можем довести задачу до конца:

heart.onclick = function () {
  // если (заполнен) 
  if (heart.classList.contains('added')) { 
    likesNumber.textContent++; // прибавить
  } else { // иначе
    likesNumber.textContent--; // убавить
  }
  heart.classList.toggle('added');
};

Готово! Как оно там работает с сервером, в плане как сохранить кол-во лайков — это я пока не знаю. Пока задачи чисто визуальные.

Комментарий

Следующая задачка — комментарий! Не весь блок комментариев, видимо, это пока сложно для начинающего, а именно реализовать добавление комментария через форму. Наверное, будет нагляднее дать скрин из задания:

Попробуем снова от общего к частому — при оправки определённой формы, нужно создать элемент, добавить его в определённый блок и вписать в этот элемент содержимое определённого поля из этой формы.

Итого нам нужно найти на странице саму форму, поле ввода и сам блок комментариев, а также подготовить стиль для комментария. В данном случае весь блок это нумерованный список <ol> и каждый комментарий — это пункт списка <li>, поэтому с этим мы и будем работать.

Находим и объявляем переменные:

let commList = document.querySelector('.list'); // блок комментариев
let commForm = document.querySelector('.form'); // форма
let commInput = document.querySelector('.input'); // поле формы

Про обработчик событий при отправке формы .onsubmit нам вскользь упоминали в прошлый раз, уже хорошо. Тут в задании, правда, какая-то конструкция в виде evt.preventDefault(); — я так понял, что это штука не дает отправить пустую форму, но про нее пока без разъяснений.

С отправкой разобрались, теперь нам нужно каким-то образом создать элемент с помощью JavaScript и нам в этом поможет метод .createElement()! Наш комментарий это пункт списка <li>, поэтому создадим его и сразу запишем в переменную:

let newComm = document.createElement('li');

Интересно, можно ли метод использовать сразу в какой-то области, а не только в документе? Беглый гуглинг дал понять, что, вроде как, нельзя. Ну и ладно.

Сам элемент создается непонятно где, наверное, в конце документа (?), поэтому теперь нам нужно явно добавить его к уже существующему блоку комментариев. В этом нам поможет метод .append(), который добавляет к указанному блоку указанный элемент:

commList.append(newComm); 

Отлично — мы только что создали и добавили пустоту! Пустой пункт списка <li> без контента и стилей. Что ж, добавлять классы мы умеем, а вот контент нам нужен определенный — из поля формы. Само поле формы мы уже нашли, но нам нужно его значение, то есть value — его и указываем!

В итоге вот что получается:

commForm.onsubmit = function (evt) { // отправка формы
  evt.preventDefault(); // что-то непонятное

  let newComm = document.createElement('li'); // создаем <li>
  newComm.classList.add('comment'); // добавляем класс
  newComm.textContent = commInput.value; // вставляем контент
  commInput.value = ''; //очищаем поле ввода
  commentList.append(newComm); // добавляем полученное в блок
};

Готово! Очистка поля это бонусное задание, но я думаю и так понятно как оно работает.

Испытание

По поводу практики — её как бы нет, есть только одно испытание и по своей сути — это комбинация того, что мы сейчас проделали. Нужно подправить код, чтобы к списку добавлялся пункт с текстом из формы, раскрашенный в зависимости от переключателя.

Готовое решение, вместе с бонусом.

Надо сказать интересное задание, пришлось чутка посидеть, попыхтеть. Очень предусмотрительно продублировали задачи в коде.

Часть 2: Коллекции и свойства элементов

Идем дальше в том же духе — нам ставят задачу, мы ее пытаемся исполнить. В этой части продолжаем мучить комментарии, но сначала отвлечёмся на создание всплывающих подсказок или Tooltip.

Tooltip

Ситуация следующая — в тексте статей периодически встречаются термины или высказывания, к которым нужно прикрутить пояснения или комментарий. Появляются они в всплывающем окне, которое за нас уже сверстали. Наша задача сделать так, чтобы при нажатии на определенный термин появлялся именно его tooltip.

Всплывающее окно появляется при добавлении ему класса opened — это мы умеем. Связать нажатие .onclick по термину с окном мы тоже сможем, надо только найти нужные селекторы терминов и записать в переменные. Верно?

let tooltipButton = document.querySelector('.tooltip-button');

Да, но только если у вас на странице только один такой tooltip, иначе работать будет только первый указанные в вёрстке — остальные не будут. Нам нужно найти их все и в этом нам поможет .querySelectorAll — который находит все указанные элементы и возвращает их набор или «коллекцию«.

Коллекция представляет собой, грубо говоря, список всех найденных элементов, которым присвоен свой индекс начиная с нуля. Через номер индекса [n], мы можем обращать к каждому в отдельности:

let tooltipButtons = document.querySelectorAll('.tooltip-button');
console.log(tooltipButtons[0]); // выводит первый элемент
console.log(tooltipButtons[1]); // выводит второй

Хорошо, получается мы можем найти все элементы с подсказками и каждому прикрутить обработчик .onclick — тогда всё будет работать? Будет, но в реальности мы никогда не знаем сколько в статье будет таких подсказок и будут ли вообще. Нужно сделать что-то универсальное, не зависящее от точного количества элементов.

Здесь на сцену выходит цикл for of! Нас предупредили, что циклов в JS много, но конкретно этот выполняет указанный в нём код столько раз, сколько элементов содержится в указанной коллекции. На примере нашей:

let tooltipButtons = document.querySelectorAll('.tooltip-button');
for (let tooltipButton of tooltipButtons) { // условия цикла
  console.log(tooltipButton); // выводит по очереди все элементы
}

Здесь непосредственно в условиях цикла мы объявляем переменную tooltipButton, которой будет присваиваться значение элемента из коллекции tooltipButtons, таким образом код внутри цикла будет исполняться для всех элементов в коллекции. Вписываем туда наш обработчик и получаем:

let tooltip = document.querySelector('.tooltip'); // окно подсказки
let tooltipButtons = document.querySelectorAll('.tooltip-button');
for (let tooltipButton of tooltipButtons) {
  tooltipButton.onclick = function () {
    tooltip.classList.add('opened');
  }; 
}

Замечательно, мы научились открывать пустое окно для каждого элемента в тексте. Теперь нужно в это окно добавить саму подсказку. И тут в тренажёре про этот нюанс упомянуто вскользь, но на мой взгляд об этом надо было хотя бы как-то упомянуть в блоке про HTML.

Текст подсказки реализован в вёрстке, с помощью эээ… специального, «кастомного» data-атрибута элемента. Оказывается, любым тегам можно задавать свои атрибуты, нужно только поставить префикс data- и называй как удобно. Я очень много встречал сайтов с тонной атрибутов у каждого тега и теперь мне стало понятно почему. Ладно, это потом.

Достать значение такого атрибута можно с помощью метода .dataset.атрибут, с несколькими нюансами при написании имени атрибута:

  • Имя атрибута указывать без префикса data-;
  • Если в названии атрибута есть несколько слов и дефисы, то в JS его записывать в «Верблюжьем стиле» — имяАтрибутаПодсказки.

У каждой кнопки с тултипом есть свой атрибут с уникальным значением, нам нужно лишь достать его и запихнуть в текстовое поле всплывающей подсказки. Находим селектор текстового поля, добавляем в наш цикл его замену:

let tooltip = document.querySelector('.tooltip'); // окно подсказки
let tooltipText = document.querySelector('.tooltip-text'); // её текст
let tooltipButtons = document.querySelectorAll('.tooltip-button');

for (let tooltipButton of tooltipButtons) {
  tooltipButton.onclick = function () {
    tooltipText.textContent = tooltipButton.dataset.tooltipText;
    tooltip.classList.add('opened');
  }; 
}

Отлично, все работает. С этим кодом нам не важно сколько на странице будет тултипов — они все будут работать благодаря циклу. Нужно только добавить кнопку закрытия окна — я ее не стал везде пихать, потому что это просто обработчик .onclick с методом classList.remove — мы уже разбирали.

Вообще, насколько я могу судить из того что сам видел — таким образом работают большинство всплывающих окон, конкретно здесь это тултип по клику на слово в тексте, но различные всплывающие формы или «спасибки» после отправки — все делается примерно по такому же алгоритму.

Делаем Twitter

Возвращаемся к комментариям! Задача ограничить количество символов при отправке комментария до 142. Для нас сверстали счётчик в виде специального элемента <output> и добавили класс warning предназначенное для формы.

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

Для этого мы используем новый обработчик событий .oninput — который выполняет указанный в нем код каждый раз когда изменяется значение в указанном поле. Таким образом мы можем «отследить» ввод, теперь нам надо узнать количество символов.

Для этого мы используем свойство .length которое как раз передает число символов в строке. Мы применим его для value поля ввода, получаем:

commInput.oninput = function () { // обработчик ввода
  console.log(commInput.value.length); // выводит текущее число символов
};

Хорошо, ключевое число символов мы нашли. Теперь нужно создать конструкцию, которая, во-первых, не позволит отправить сообщение если оно превышает указанное, во-вторых наглядно вывести текущее число символов и применить предупреждающий стиль warning для формы.

Область комментариев, форму отправки и поле этой формы у нас уже найдено, обработчик отправки .onsubmit и по вводу .oninput уже тоже есть. Как нам запретить отправку формы? Можно заблокировать кнопку «Отправить»!

Заблокировать ее можно с помощью свойства .disabled которое принимает уже знакомые нам True и False. Всё остальное мы уже знаем и умеем, а значит пора все собрать в кучу!

Находим кнопку и счётчик, объявляем переменные и сразу мастерим условную конструкцию if {} else {} используя полученное число символов:

let commList = document.querySelector('.list'); // блок комментариев
let commForm = document.querySelector('.form'); // форма
let commInput = document.querySelector('.input'); // поле формы
let commCounter = document.querySelector('.counter'); // счётчик
let subButton = document.querySelector('.submit'); // кнопка

commInput.oninput = function () {
  charCounter.textContent = commentField.value.length; // обнавляем счётчик
  
  if (commInput.value.length > 142) { // если превышает 142
    commForm.classList.add('warning'); 
    subButton.disabled = true; // блокируем кнопку
  } else {
    commForm.classList.remove('warning'); // если не превышает
    subButton.disabled = false;
  }
};

Вот как все выглядит в итоге:

Кнопка заблокирована, поле, подпись и счетчик окрашены, счетчик показывает число символов.

Осталась небольшая проблема — после корректной отправки комментария у нас не обнуляется счетчик. Это обнуление можно воткнуть в .onsubmit присвоив контенту счетчика значение = 0.

Испытание

Очень прикольное испытание в этой части! Нужно реализовать работу клавиатуры на экране. Все сверстано, понятное дело, даны классы и пояснения что должно получится.

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

Часть 3: Прокрутка и операторы

Снова две задачки и два новых обработчика событий. Одна из них тривиальная — добавить кнопку «Наверх» при скролле вниз, вторая на первый взгляд сложная, по крайней мере я, намучившийся с WordPress и их таксономиями, сразу напрягся, но в нашем случае всё намного проще!

Кнопка «Наверх»

Задача не просто сделать кнопку «наверх», иначе можно было её сделать просто через якорь, а сделать так, чтобы она появлялась при прокрутке вниз на 200px и исчезала если такой прокрутки нет.

Нас сразу знакомят с обработчиком событий прокрутки .onscroll — он срабатывает при малейшей прокрутки страницы, причем как по вертикали, так и по горизонтали, если это предусмотрено на страницу.

Отследить скролл можем, теперь нужно количественно его определить. Для этого используем свойство .pageYOffset которое применяется к окну браузера window и полная запись выглядит вот так:

console.log(window.pageYOffset); // выведет число px верт. прокрутки

За горизонтальную прокрутку отвечает .pageXOffset, но нам он сейчас не нужен, да и вообще он достаточно редко нужен, наверное. Хотя, я также думал про таблицы в HTML.

Хорошо, мы знаем как отследить скролл и его точное количество пикселей, мы уже можем построить условную конструкцию для появления кнопки. Но нам надо, чтобы она заработала — возвращала страницу наверх по нажатию на нее.

Для этого есть метод .scrollTo(X, Y) — он «отправляет» область просмотра к указанным координатам, выравненным по левому верхнему углу. Тут будет проще показать картинку из урока:

window.scrollTo(100, 50);
X координата по горизонтали, Y по вертикали

Теперь у нас точно всё есть! Нам нужно найти кнопку и сделать два обработчика — один на скролл, что бы показать кнопку, второй на клик по этой кнопке. И не забыть скрыть её если скролл меньше 200 px. В итоге получается:

let upButton = document.querySelector('.up-button'); // кнопка

window.onscroll = function () { // событие на скролл
  if (window.pageYOffset > 200) { // проверка прокрутки
    upButton.classList.add('shown');
  } else {
    upButton.classList.remove('shown');
    }
};

upButton.onclick = function () { 
  window.scrollTo(0, 0); // отправляем к верхнему левому углу
};

Пока что это самое простое задание из блока, хотя, это кажется после сложных комментариев. Но дальше задачка еще сложнее.

Фильтр контента

Если точнее — нужно сделать фильтр публикаций в ленте по категориям. Такая задача может быть реализована очень по разному — дофига факторов к этому.

В нашем случае мы, понятное дело, реализуем через JS. Будем использовать data-атрибут у блоков новостей, отвечающий за их категорию — у каждого блока в вёрстке заранее прописан этот атрибут со значением определенной категории. Таким образом мы сможем потенциально их различить, ведь как обращаться к data-атрибутам мы уже знаем.

Сама фильтрация будет через выпадающее меню <select>, где пункты соответствуют конкретной категории и отдельно пункт «Все новости», который нам тоже надо реализовать.

Итак, у нас складывается картина — есть какое-то количество новостей и фильтрующий элемент. Для начала найдем их — нам нужны все новости, поэтому находим все селекторы на странице:

let articles = document.querySelectorAll('.news-block'); // новости
let filter = document.querySelector('.filter'); // меню фильтра

Дальше как нам их связать? С помощью нового для нас обработчика событий .onchange, который срабатывает каждый раз, когда значение указанного элемента изменяется.

В нашем случае изменяется выбранная опция выпадающего меню — к нему мы и будем обращаться! Итак, дальше нам нужно, чтобы при выборе пункта меню, проверялось соответствие выбранной категории к указанной категории новости в data-атрибуте и если они совпадают — показать новость, а остальные скрыть.

Про свойство .dataset мы знаем, условную конструкцию if () {} else {} тоже уже несколько раз использовали. Кажется вроде всё есть, но дойдя до условия окажется, что есть нюансы.

В JS есть различные операторы соответствия — «равно» или «не равно» может быть строгим и нестрогим, а еще просто символ «=» это не «равно».

num1 === num2 // строгое равенство (три равно подряд)
num1 !== num2 // строгое неравенство (! и два равно)
num1 == num2  // нестрогое равенство (два равно)
num1 != num2  // нестрогое неравенство (! и равно)

// Ох уж это форматирование операторов здесь. Вот нахрена?

В тренажере не особо вдаются в подробности различия строгих и нестрогих операторов, но для нас сейчас важны именно строгие. С их помощью мы сможем написать условную конструкцию, которая будет проверять соответствие атрибута у новости с текущим значением выпадающего меню.

Итого у нас получается:

filter.onchange = function () { // меняем пункт меню
  for (let article of articles) {
    if (article.dataset.category !== filter.value) { // проверяет атрибут
      article.classList.add('hidden'); // если его нет - скрывает
    } else {
      article.classList.remove('hidden'); // иначе показывает
    }
  }
};

Отлично, всё работает кроме пункта «Все новости» — при его выборе новости пропадают, а должно быть наоборот. Действительно, ведь этот пункт попадает под условие скрытия. Нужно дополнить условие и в этом нам поможет еще один оператор Логическое И && (два амперсанда).

Используя его, мы дополняем условие еще одним параметром. Я немного перенесу строки, чтобы уместилось и было наглядно:

filter.onchange = function () { // меняем пункт меню
  for (let article of articles) {
    if (
    article.dataset.category !== filter.value // первое условие
    && // Логическое И
    filter.value !== 'all' // Второе условие
       ) {
      article.classList.add('hidden');
    } else {
      article.classList.remove('hidden');
    }
  }
};

Готово! Таким образом, условие гласит — «Скрыть если не соответствует выбранной категории И если не выбрано 'all'» — то, что нам нужно.

Испытание

Задача в испытании — настроить цензуру! Форма отзыва с радио-кнопками, некоторые пункты положительного характера, некоторые отрицательного. Они так и помечены 'good' и 'bad' в специальном data-атрибуте.

Вжух! И только позитивная повестка!

Пришлось немножко потупить в монитор. Именно потупить, несколько раз прочитать задание. Основной «ловушкой» здесь является то, что в течение прохождения тренажёра у нас цикл внутри обработчика, а здесь надо сделать наоборот.

Часть 4: Динамические стили элементов

В заключительной части тоже две задачи, хотя, во второй две как бы отдельные подзадачи. Но ничего — справимся! Будем с помощью JS менять значения свойств из CSS и показывать всем свой пароль.

Настройки стиля

У статей из заданий появились настройки стилей — ползунок с размером текста два выпадающих меню с цветом текста и фона, а наша задача с помощью JS реализовать их работоспособность.

С дроп-меню мы уже знакомы, а ползунок еще не встречали, причем, даже в блоке про HTML. Тут нас с ним легонечко знакомят — это <input> типа type="range", который так же принимает атрибуты минимального и максимального значения min="" и max="", а еще шаг step="".

В нашем случае диапазон настройки размера текста от 8px до 48px с шагом 1px. Не будем на нём заострять внимание, я уверен, еще на заостряемся в следующих блоках.

На сцену выходит свойство .style, которое обращается к указанному CSS свойству элемента. В CSS, правда, очень много свойств записано через дефис и здесь, как и в случае data-атрибутов, записывать нужно в «верблюжьем» стиле. То есть обращение к background-color будет выглядеть так:

someElement.style.backgroundColor

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

let longread = document.querySelector('.longread'); // статья
let colorSetting = document.querySelector('.color-setting'); // цвет текста
let bgSetting = document.querySelector('.bg-setting'); // цвет фона
let sizeSetting = document.querySelector('.size-setting'); // ползунок
let pixels = document.querySelector('.pixels'); // счетчик ползунка

Дальше просто — у всех настроек есть value, хватаем его, пихаем в обработчик событий .onchange и все будет работать! Да, но опять есть нюанс.

Если мы применим .onchange для ползунка, то окончательно применятся стиль, то бишь выполняться скрипт в обработчике, будет только после отпускания левой кнопки мыши. Соответственно, изменение размера текста будет не достаточно наглядным.

С ползунком лучше подойдет обработчик событий .oninput который срабатывает при каждом изменении значения, то бишь каждый шаг step="". Таким образом размер текста будет изменятся более плавно.

Теперь собираем всё в кучу:

colorSetting.onchange = function () { // цвет текста
  longread.style.color = colorSetting.value;
};

bgSetting.onchange = function () { // цвет фона
  longread.style.backgroundColor = bgSetting.value;
};

sizeSetting.oninput = function () { // размер текста
  pixels.textContent = sizeSetting.value; // счетчик
  longread.style.fontSize = sizeSetting.value + 'px'; // не забыть про px!
};

Задача относительно простая, особенно учитывая пройденные выше этапы. Но здесь вся часть больше на нюансы и важные свойства, чем на новые функции, что тоже крайне важно.

Покажи пароль, а если найду?

Следующая задача содержит в себе две подзадачи, обе связаны с полем ввода пароля в форме регистрации. Из прошлого блока мы знаем про различные типа полей, в том числе поле с паролем type="password", который по умолчанию скрывает вводимую информацию, заменяя символы звёздочками.

Но иногда пароль не qwerty123 и нужно проверить правильность его написания, особенно при регистрации на сайте. Для этого нам нужна кнопка или, в нашем случае, переключатель, показывающий что же мы там ввели.

Для этой задачи в JS есть одноименные с HTML атрибуты и свойства — это свойство .type, которые, очевидно, обращается к одноименному атрибуту элемента. А так же, так как для скрипта на понадобится условная проверка переключателя, в JS есть свойство .checked, который проверяет наличие этого атрибута у элемента, то есть проверяет наличие галочки у чекбокса.

Итак компоненты у нас есть, надо свести их в одну конструкцию. Находим само поле и переключатель, затем проверяем состояние переключателя и в зависимости от результата меняем тип поля. Получается:

let password = document.querySelector('.password'); // поле пароля
let showPassword = document.querySelector('.show-password'); // чекбокс

showPassword.onchange = function () { 
  if (showPassword.checked) { // вкл. показать пароль
    password.type = 'text'; // меняем на текстовое поле
  } else { // выкл. показ пароля
    password.type = 'password';
  }
};

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


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

Подумаем что нам для этого надо. Узнать длину пароля с помощью .value.length мы сможем. Перекрасить полоску с помощью .style — тоже разберёмся. Мы не знаем как менять размер полоски, но дедуктивным методом можно предположить, что CSS свойство width мы тоже можем вызвать через свойство .style — проверим!

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

То есть условия три, а мы до этого разбирали только два. Но всё решается достаточно просто — уловная конструкция может быть расширена с помощью промежуточного условия else if () {} и таких условий может быть сколько требует конкретная задача.

Про уловные и математические операторы — большем, меньше, умножить и так далее, я отдельно писать не буду, так как они работают очевидно. Давайте соберем все в кучу, выше мы уже нашли поле пароля и чекбокс, осталось найти саму полоску и написать для нее обработчик событий с условной конструкцией:

let securityBar = document.querySelector('.security-bar');

password.oninput = function () { 
  // длину пароля записываем в переменную, для удобства
  let passLength = password.value.length;
  
  // ширина полоски рассчитывается в % ширины контейнера
  securityBar.style.width = passLength * 10 + '%'; // 1 символ = 10%
  
  if (passLength <= 5) { // < и = (опять форматирование)
    securityBar.style.backgroundColor = 'red';
  } else if (passLength > 5 && passLength < 10) { // от 6 до 9 включ.
    securityBar.style.backgroundColor = 'gold';
  } else { // 10 и больше
    securityBar.style.backgroundColor = 'green';
    }
};

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

В итоге всё работает — мы великолепны! Общий скрипт задачи вместе с показом пароля достаточно длинный, я не буду его копировать — это компиляция двух блоков выше.

Испытание

Очень крутое испытание — пишем свой аналог Photoshop для бедных! Есть поле в котором есть «пиксели» — это квадратные <div>'ы определённого размера, есть дроп-меню с цветами и «ластик», который на самом деле просто белый цвет.

Задачка тоже из разряда «потупить 10 минут», то есть сначала все в голове сложить, а потом уже писать код. Я сначала еще по выпендривался с записью переменной в обработчике, но что-то у меня не сработало. Скорее всего, её надо было выводить из обработчика под for. Главное решил.


Вот мы и закончили "Знакомство с JavaScript". Надо сказать было очень интересно, я прям в восторге от этой части, намного больше понравилась чем "Знакомство с HTML и CSS". Возможно, это из-за того, что я её затянул.

Вообще, я теперь понимаю, почему иногда в разговоре со знакомыми веб-разработчиками я видел очень разную реакцию на HTML/CSS и на JS. JavaScript элементарно интереснее, на мой взгляд. Но я все еще в начале пути, будем смотреть, может есть подводные камни.

Спасибо большое тем героям, что дочитали эту колбасень текста, получилось реально дофига, но я уже начал привыкать столько строчить. Надо было идти на журфак, а не на эти ваши физики. Шучу.

Ссылки на остальные статьи по HTML Academy:

Знакомство с Веб-разработкой
Знакомство с HTML и CSS
Знакомство с JavaScript <- Вы здесь
Знакомство с PHP
Таблицы и подробно о формах
Наследование, каскады и селекторы
Блочная модель, поток и сетка на float
Гибкие флексбоксы display: flex
Удобные сетки на гридах display: grid
Пропуск блока «Погружение»
Позиционирование и двумерные трансформации
Теневое искусство и линейные градиенты
CSS-фильтры и Кекстаграм
Мастерские
Продвинутые Мастерские
...

Остальные статьи можно посмотреть у меня на главной странице блога.

Также мои соц. сетки, которые я продолжаю вести:

Мой Twitter
Мой Telegram
Мой Паблик ВК

Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!