-
Notifications
You must be signed in to change notification settings - Fork 649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Добавляет рецепт рейтинга 5 ⭐️ #5592
base: main
Are you sure you want to change the base?
Conversation
Чек-лист для новой статьиМетаданные
Статья
|
<legend>Оцените товар:</legend> | ||
<ul class="stars"> | ||
<li class="star"> | ||
<button><span class="visually-hidden">5 звёзд</span>⭐️</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<button>
без type="button"
будет автоматически отправлять форму, если встроить этот блок в форму. А это основной кейс
Но вообще, мне кажется лучше сделать выбор радио кнопками. Тогда и не нужно будет писать логику выбора, при отправке формы можно будет считать из FormData
. И не нужно будет имитировать радио кнопки всякими aria аттрибутами, потому радио кнопки древний элемент и поддерживаются везде 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Привет, красота 🤩
Оставил несколько комментов, и будет космическая ракета!
related: | ||
- css/hover | ||
- js/query-selector | ||
- css/cascade/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Давай тут приведём к единому виду?
- css/cascade/ | |
- css/cascade |
|
||
## Задача | ||
|
||
Создать компонент, состоящий из 5 звезд. На любую из звёзд можно кликнуть и все звёзды до неё и она сама станут отмеченными, активными. Если кликнуть на эту звезду второй раз, то все звёзды снова станут неактивными. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. При этом когда курсор убирается кликнутые звёзды остаются активными. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Создать компонент, состоящий из 5 звезд. На любую из звёзд можно кликнуть и все звёзды до неё и она сама станут отмеченными, активными. Если кликнуть на эту звезду второй раз, то все звёзды снова станут неактивными. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. При этом когда курсор убирается кликнутые звёзды остаются активными. | |
Создать компонент, состоящий из 5 звёзд. На любую из звёзд можно кликнуть, и все звёзды до неё и она сама станут отмеченными, активными. Если кликнуть на эту звезду второй раз, то все звёзды снова станут неактивными. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. При этом, когда курсор убирается, кликнутые звёзды остаются активными. |
Разметка: | ||
|
||
```html | ||
<fieldset class="star-rating" role="radiogroup" data-rating-value=""> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Если мы указываем role="radiogroup"
, то внутри должны быть элементы с ролями radio, или проще наверное с нативным input type="radio"
. Го добавим тут?
const rating = document.querySelector('.star-rating') | ||
const stars = document.querySelectorAll('.star') | ||
|
||
stars.forEach((star, index) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вот тут и далее мы ведь не используем параметр index
? Давай тогда чуть упростим:
stars.forEach((star, index) => { | |
stars.forEach(star => { |
</ul> | ||
``` | ||
|
||
Чтобы скринридеры воспринимали элемент целиком и зачитывали его подпись используем связку [`<fieldset>`](/html/fieldset/) + [`<legend>`](/html/legend/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Чтобы скринридеры воспринимали элемент целиком и зачитывали его подпись используем связку [`<fieldset>`](/html/fieldset/) + [`<legend>`](/html/legend/). | |
Чтобы скринридеры воспринимали элемент целиком и зачитывали его подпись, используем связку [`<fieldset>`](/html/fieldset/) + [`<legend>`](/html/legend/). |
|
||
<iframe title="Обработка клика со стилями" src="demos/js-2/" height="400"></iframe> | ||
|
||
Теперь сделаем так, чтобы при повторном клике оценка убиралась и все звёзды снова становились неактивными. Для этого добавим проверку, есть ли класс `active` у звезды на которую кликнули или нет. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Теперь сделаем так, чтобы при повторном клике оценка убиралась и все звёзды снова становились неактивными. Для этого добавим проверку, есть ли класс `active` у звезды на которую кликнули или нет. | |
Теперь сделаем так, чтобы при повторном клике оценка убиралась и все звёзды снова становились неактивными. Для этого добавим проверку, есть ли класс `active` у звезды, на которую кликнули, или нет. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
может не "убиралась", а "исчезала"?
|
||
<iframe title="Обработка клика в обе стороны" src="demos/js-3/" height="400"></iframe> | ||
|
||
Добавим пару строк чтобы менялось значение атрибута `data-rating-value` в зависимости от того, какая звезда выбрана. Для этого используем свойство [`.dataset`](/js/element-dataset/) и будем _читать_ значение скрытого текста, доставать оттуда цифру при помощи [`parseInt()`](/js/parseint/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Добавим пару строк чтобы менялось значение атрибута `data-rating-value` в зависимости от того, какая звезда выбрана. Для этого используем свойство [`.dataset`](/js/element-dataset/) и будем _читать_ значение скрытого текста, доставать оттуда цифру при помощи [`parseInt()`](/js/parseint/). | |
Добавим пару строк, чтобы менялось значение атрибута `data-rating-value` в зависимости от того, какая звезда выбрана. Для этого используем свойство [`.dataset`](/js/element-dataset/) и _прочтём_ значение скрытого текста, а достанем оттуда цифру при помощи [`parseInt()`](/js/parseint/). |
|
||
Осталось реализовать последнее требование. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. Это условие должно работать вне зависимости от того, какой рейтинг сейчас выбран. | ||
|
||
Для этого немного схитрим и будем делать полупрозрачными все звёзды если курсор находится в пределах родительского блока `.stars`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Для этого немного схитрим и будем делать полупрозрачными все звёзды если курсор находится в пределах родительского блока `.stars`. | |
Для этого немного схитрим и будем делать полупрозрачными все звёзды, если курсор находится в пределах родительского блока `.stars`. |
} | ||
``` | ||
|
||
Теперь доработаем правило для [`:hover`](/css/hover/), которе уже было в CSS. Увеличим вес селектора при помощи класса `.stars` в начале и обязательно подвинем его вниз, под предыдущее правило. Это нужно из-за [принципа каскада](/css/cascade/). Иначе правила начнут перебивать друг друга. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Теперь доработаем правило для [`:hover`](/css/hover/), которе уже было в CSS. Увеличим вес селектора при помощи класса `.stars` в начале и обязательно подвинем его вниз, под предыдущее правило. Это нужно из-за [принципа каскада](/css/cascade/). Иначе правила начнут перебивать друг друга. | |
Теперь доработаем правило для [`:hover`](/css/hover/), которое уже было в CSS. Увеличим вес селектора при помощи класса `.stars` в начале и обязательно подвинем его вниз, под предыдущее правило. Это нужно из-за [принципа каскада](/css/cascade/). Иначе правила начнут перебивать друг друга. |
|
||
Обратите внимание, что элементы идут в разметке в обратном порядке. Это связано с особенностями работы CSS. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Микро-правочка
} | ||
``` | ||
|
||
<iframe title="Ховер при выбраном рейтинге" src="demos/js-css/" height="400"></iframe> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Кажется всё таки два «н».
<iframe title="Ховер при выбраном рейтинге" src="demos/js-css/" height="400"></iframe> | |
<iframe title="Ховер при выбранном рейтинге" src="demos/js-css/" height="400"></iframe> |
<!DOCTYPE html> | ||
<html lang="ru"> | ||
<head> | ||
<title>Ховер при выбраном рейтинге — Рейтинг «5 звёзд» — Дока</title> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<title>Ховер при выбраном рейтинге — Рейтинг «5 звёзд» — Дока</title> | |
<title>Ховер при выбранном рейтинге — Рейтинг «5 звёзд» — Дока</title> |
## HTML | ||
|
||
В первую очередь создадим HTML-разметку для рейтинга. Элементы связаны по смыслу, поэтому нужно использовать подходящий семантический тег. Также для нативной поддержки фокуса используем тег [`<button>`](/html/button/). Понадобиться 5 пунктов списка с вложенными кнопками. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
понадобится, без мягкого знака
Валидирую и всячески одобряю! Сделала шрифт побольше. В код готового решения добавила эти стили, если не нужны там, фил фри убрать :) |
Превью контента из a2a0058 опубликовано. |
const stars = document.querySelectorAll('.star') | ||
|
||
stars.forEach((star, index) => { | ||
star.addEventListener('click', (event) => { | ||
const activeStar = event.currentTarget | ||
|
||
if (activeStar.classList.contains('active')) { | ||
activeStar.classList.remove('active') | ||
rating.dataset.ratingValue = '' | ||
} else { | ||
stars.forEach(star => star.classList.remove('active')) | ||
activeStar.classList.add('active') | ||
rating.dataset.ratingValue = parseInt(activeStar.textContent.trim()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Привет,
Классные звёздочки ! Ставлю: ⭐⭐⭐⭐⭐
В скрипте можно немножко сэкономить:
const rating = document.querySelector('.star-rating')
// дочерние элименты ищем локально
const starsContainer = rating.querySelector('.stars')
const stars = rating.querySelectorAll('.star')
// добавляем один EventListener к элементу ul
starsContainer.addEventListener('click', (event) => {
// получаем звезду на которой произошёл клик
const activeStar = event.target.closest('.star')
...
Попалась мне тут задачка на собеседовании и я решила написать по её следам рецепт. Вариантов решения этой задачи в интернете много. Но этот показался мне самым оптимальным.
@TatianaFokina очень интересно будет узнать твои рекомендации по доступности такого элемента 🙏
@skorobaeus приходи завалидировать демки =)