Добрый день, Хабр! Решил поделиться своим небольшим, но полезным открытием в плане использования html data-attributes & css selectors.
Html data-attributes — это кастомные атрибуты, которые вы можете сами назначать куда-угодно и с каким угодно именем (но имя должно начинаться с префикса data-). Затем вы можете использовать их в css селекторах, чтобы влиять на содержимое классов и уже классами управлять элементами. Движок браузера автоматически среагирует на изменение data-атрибута и применит соответствующий код css класса.
Код реакт компоненты, где по нажатию кнопки что-то скрывается, что-то показывается:
import React, {useState} from "react"; const ComponentWithExpandableContent = () => { const [expanded, setExpanded] = useState(false) return <div style={{ display: 'flex', flexFlow: 'column nowrap', alignItems: 'start', padding: 32, gap: 32, }}> { !expanded && <div>Initial content</div> } <button onClick={()=>setExpanded(!expanded)}> { !expanded ? 'Expand' : 'Collapse' } </button> { expanded && <div>Additional content</div> } { expanded && <div>More additional content</div> } </div> } export default React.memo(ComponentWithExpandableContent)
Состояние expanded=false:

Состояние expanded=true:

Теперь просто html css js.
Файл emulating-use-state.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> Эмулируем React useState в обычном JS (via data-attributes & css selectors) </title> <link rel="stylesheet" type="text/css" href="emulating-use-state.css"> </head> <body> <script> function toggleExpand(){ const element = document.getElementById('component') if (element.dataset.expanded!=='true'){ element.dataset.expanded = 'true' } else { element.dataset.expanded = 'false' } } </script> <div class="someElementContext"> <!-- data-expanded хранит состояние --> <div id="component" class="component" data-expanded="false"> <div class="collapsableContent"> <div>Initial content</div> </div> <button onClick="toggleExpand()"> <div class="collapsableContent">Expand</div> <div class="expandableContent">Collapse</div> </button> <div class="expandableContent"> <div>Additional content</div> </div> <div class="expandableContent"> <div>More additional content</div> </div> </div> </div> </body> </html>
Файл стилей emulating-use-state.scss:
.someElementContext { display: contents; .component { display: flex; flex-flow: column nowrap; align-items: start; padding: 32px; gap: 32px; // Классы, управляющие видимостью элементов на странице // в зависимости от текущего значения data-expanded .expandableContent { display: none; } .collapsableContent { display: contents; } &[data-expanded=true] .expandableContent { display: contents; } &[data-expanded=true] .collapsableContent { display: none; } } }
Сгенерированный средой разработки emulating-use-state.css:
.someElementContext { display: contents; } .someElementContext .component { display: flex; flex-flow: column nowrap; align-items: start; padding: 32px; gap: 32px; } .someElementContext .component .expandableContent { display: none; } .someElementContext .component .collapsableContent { display: contents; } .someElementContext .component[data-expanded=true] .expandableContent { display: contents; } .someElementContext .component[data-expanded=true] .collapsableContent { display: none; }
Получилось поведение аналогичное описанному в реакт компоненте.
Здесь в качестве стэйта выступает кастомный data-атрибут data-expanded — он и хранит состояние. А css селектор [data-expanded=true] изменяет свойство display из none в contents (display: contents означает показывать содержимое элемента так, как будто самого элемента не существует) и обратно в специальных классах-обёртках .expandableContent & .collapsableContent, которыми можно просто обернуть любые элементы в html разметке.
ссылка на оригинал статьи https://habr.com/ru/post/708822/
Добавить комментарий