Skip to content
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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

solarrust
Copy link
Member

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

@TatianaFokina очень интересно будет узнать твои рекомендации по доступности такого элемента 🙏

@skorobaeus приходи завалидировать демки =)

@solarrust solarrust added статья Расширенный материал рецепт Контент для Рецептов labels Dec 11, 2024
Copy link

github-actions bot commented Dec 11, 2024

Чек-лист для новой статьи

Метаданные

  • Код в поле title завёрнут в бэктики
  • Есть поле description с описанием
  • Проставлен тег article
  • Поле keywords содержит ключевые слова, которых нет в тексте статьи
  • В поле authors указан автор. Файл автора есть в папке people
  • В поле related есть ссылки на материалы Доки, интересные в контексте данного (не более трёх)

Статья

  • Структура совпадает с шаблоном
  • Демки написаны по рекомендациям
  • У картинок есть описание в alt, у фреймов демок название в title
  • Статья добавлена в содержание раздела
  • Для статьи указаны материалы Доки, интересные для дальнейшего чтения

<legend>Оцените товар:</legend>
<ul class="stars">
<li class="star">
<button><span class="visually-hidden">5 звёзд</span>⭐️</button>
Copy link
Contributor

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 аттрибутами, потому радио кнопки древний элемент и поддерживаются везде 👍

Copy link
Member

@Inventoris Inventoris left a 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/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Давай тут приведём к единому виду?

Suggested change
- css/cascade/
- css/cascade


## Задача

Создать компонент, состоящий из 5 звезд. На любую из звёзд можно кликнуть и все звёзды до неё и она сама станут отмеченными, активными. Если кликнуть на эту звезду второй раз, то все звёзды снова станут неактивными. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. При этом когда курсор убирается кликнутые звёзды остаются активными.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Создать компонент, состоящий из 5 звезд. На любую из звёзд можно кликнуть и все звёзды до неё и она сама станут отмеченными, активными. Если кликнуть на эту звезду второй раз, то все звёзды снова станут неактивными. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. При этом когда курсор убирается кликнутые звёзды остаются активными.
Создать компонент, состоящий из 5 звёзд. На любую из звёзд можно кликнуть, и все звёзды до неё и она сама станут отмеченными, активными. Если кликнуть на эту звезду второй раз, то все звёзды снова станут неактивными. По наведению курсора на любую звезду все элементы до неё и она сама становятся активными. При этом, когда курсор убирается, кликнутые звёзды остаются активными.

Разметка:

```html
<fieldset class="star-rating" role="radiogroup" data-rating-value="">
Copy link
Member

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) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вот тут и далее мы ведь не используем параметр index? Давай тогда чуть упростим:

Suggested change
stars.forEach((star, index) => {
stars.forEach(star => {

</ul>
```

Чтобы скринридеры воспринимали элемент целиком и зачитывали его подпись используем связку [`<fieldset>`](/html/fieldset/) + [`<legend>`](/html/legend/).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Чтобы скринридеры воспринимали элемент целиком и зачитывали его подпись используем связку [`<fieldset>`](/html/fieldset/) + [`<legend>`](/html/legend/).
Чтобы скринридеры воспринимали элемент целиком и зачитывали его подпись, используем связку [`<fieldset>`](/html/fieldset/) + [`<legend>`](/html/legend/).


<iframe title="Обработка клика со стилями" src="demos/js-2/" height="400"></iframe>

Теперь сделаем так, чтобы при повторном клике оценка убиралась и все звёзды снова становились неактивными. Для этого добавим проверку, есть ли класс `active` у звезды на которую кликнули или нет.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Теперь сделаем так, чтобы при повторном клике оценка убиралась и все звёзды снова становились неактивными. Для этого добавим проверку, есть ли класс `active` у звезды на которую кликнули или нет.
Теперь сделаем так, чтобы при повторном клике оценка убиралась и все звёзды снова становились неактивными. Для этого добавим проверку, есть ли класс `active` у звезды, на которую кликнули, или нет.

Copy link
Contributor

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/).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Добавим пару строк чтобы менялось значение атрибута `data-rating-value` в зависимости от того, какая звезда выбрана. Для этого используем свойство [`.dataset`](/js/element-dataset/) и будем _читать_ значение скрытого текста, доставать оттуда цифру при помощи [`parseInt()`](/js/parseint/).
Добавим пару строк, чтобы менялось значение атрибута `data-rating-value` в зависимости от того, какая звезда выбрана. Для этого используем свойство [`.dataset`](/js/element-dataset/) и _прочтём_ значение скрытого текста, а достанем оттуда цифру при помощи [`parseInt()`](/js/parseint/).


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

Для этого немного схитрим и будем делать полупрозрачными все звёзды если курсор находится в пределах родительского блока `.stars`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Для этого немного схитрим и будем делать полупрозрачными все звёзды если курсор находится в пределах родительского блока `.stars`.
Для этого немного схитрим и будем делать полупрозрачными все звёзды, если курсор находится в пределах родительского блока `.stars`.

}
```

Теперь доработаем правило для [`:hover`](/css/hover/), которе уже было в CSS. Увеличим вес селектора при помощи класса `.stars` в начале и обязательно подвинем его вниз, под предыдущее правило. Это нужно из-за [принципа каскада](/css/cascade/). Иначе правила начнут перебивать друг друга.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Теперь доработаем правило для [`:hover`](/css/hover/), которе уже было в CSS. Увеличим вес селектора при помощи класса `.stars` в начале и обязательно подвинем его вниз, под предыдущее правило. Это нужно из-за [принципа каскада](/css/cascade/). Иначе правила начнут перебивать друг друга.
Теперь доработаем правило для [`:hover`](/css/hover/), которое уже было в CSS. Увеличим вес селектора при помощи класса `.stars` в начале и обязательно подвинем его вниз, под предыдущее правило. Это нужно из-за [принципа каскада](/css/cascade/). Иначе правила начнут перебивать друг друга.


Обратите внимание, что элементы идут в разметке в обратном порядке. Это связано с особенностями работы CSS.


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Copy link
Member

@Inventoris Inventoris left a 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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется всё таки два «н».

Suggested change
<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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<title>Ховер при выбраном рейтинге — Рейтинг «5 звёзд» — Дока</title>
<title>Ховер при выбранном рейтинге — Рейтинг «5 звёзд» — Дока</title>

## HTML

В первую очередь создадим HTML-разметку для рейтинга. Элементы связаны по смыслу, поэтому нужно использовать подходящий семантический тег. Также для нативной поддержки фокуса используем тег [`<button>`](/html/button/). Понадобиться 5 пунктов списка с вложенными кнопками.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

понадобится, без мягкого знака

@skorobaeus
Copy link
Member

@skorobaeus приходи завалидировать демки =)

Валидирую и всячески одобряю!

Сделала шрифт побольше. В код готового решения добавила эти стили, если не нужны там, фил фри убрать :)

Copy link

Превью контента из a2a0058 опубликовано.

Comment on lines +117 to +130
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())
}
Copy link
Contributor

@vitya-ne vitya-ne Dec 13, 2024

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')
      ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
рецепт Контент для Рецептов статья Расширенный материал
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants