Створення сумісних веб-компонентів, які навіть працюють із React PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Створення взаємодіючих веб-компонентів, які працюють навіть із React

Ті з нас, хто працює веб-розробниками більше кількох років, ймовірно, писали код, використовуючи більше ніж одну платформу JavaScript. З усіма доступними варіантами — React, Svelte, Vue, Angular, Solid — це все майже неминуче. Однією з найбільш неприємних речей, з якими ми маємо справу, коли працюємо між фреймворками, є повторне створення всіх тих низькорівневих компонентів інтерфейсу користувача: кнопок, вкладок, спадних меню тощо. , скажімо React, але потім їх потрібно переписати, якщо ми хочемо створити щось у Svelte. Або Vue. Або твердий. І так далі.

Чи не було б краще, якби ми могли визначити ці низькорівневі компоненти інтерфейсу користувача один раз, не залежно від фреймворків, а потім повторно використовувати їх між фреймворками? Звичайно, було б! І ми можемо; веб-компоненти – це шлях. Цей пост покаже вам, як.

На даний момент історії SSR для веб-компонентів трохи бракує. Декларативний тіньовий DOM (DSD) — це те, як веб-компонент відображається на стороні сервера, але на момент написання цієї статті він не інтегрований з вашими улюбленими фреймворками програм, такими як Next, Remix або SvelteKit. Якщо для вас це вимога, обов’язково перевірте останній статус DSD. Але в іншому випадку, якщо ви не використовуєте SSR, читайте далі.

По-перше, деякий контекст

Веб-компоненти — це, по суті, елементи HTML, які ви самі визначаєте <yummy-pizza> або що завгодно, з нуля. Вони висвітлені тут, на CSS-Tricks (включаючи велика серія Калеба Вільямса та один від Джона Реа), але ми коротко розглянемо цей процес. По суті, ви визначаєте клас JavaScript, успадковуєте його від HTMLElement, а потім визначте будь-які властивості, атрибути та стилі веб-компонента і, звичайно, розмітку, яку він в кінцевому підсумку надасть вашим користувачам.

Можливість визначати користувацькі елементи HTML, які не прив’язані до жодного конкретного компонента, дуже цікаво. Але ця свобода також є обмеженням. Існування незалежно від будь-якої фреймворку JavaScript означає, що ви не можете реально взаємодіяти з цими фреймворками JavaScript. Подумайте про компонент React, який отримує деякі дані, а потім відтворює деякі інший Компонент React, передаючи дані. Це насправді не працюватиме як веб-компонент, оскільки веб-компонент не знає, як відтворити компонент React.

Веб-компоненти особливо відмінні як компоненти листя. Компоненти листя є останнім, що відображається в дереві компонентів. Це компоненти, які отримують деякі реквізити, а деякі відображають UI. Це такі НЕ компоненти, розташовані в середині вашого дерева компонентів, передають дані, встановлюють контекст тощо — просто чисті шматки UI це буде виглядати однаково, незалежно від того, який фреймворк JavaScript забезпечує живлення решти програми.

Веб-компонент, який ми створюємо

Замість того, щоб створювати щось нудне (і поширене), як-от кнопку, давайте створимо щось трохи інше. В моєму загрузка повідомлення ми розглянули використання попереднього перегляду розмитих зображень, щоб запобігти повторному перегляду вмісту та забезпечити гідний інтерфейс користувача під час завантаження зображень. Ми розглянули base64, який кодує розмиті, деградовані версії наших зображень і показує це в нашому інтерфейсі під час завантаження реального зображення. Ми також розглянули створення неймовірно компактних, розмитих попередніх переглядів за допомогою інструмента під назвою Помутніння.

Ця публікація показала вам, як створити ці попередні перегляди та використовувати їх у проекті React. Ця публікація покаже вам, як використовувати ці попередні перегляди з веб-компонента, щоб ними можна було користуватися будь-який Фреймворк JavaScript.

Але нам потрібно пройти, перш ніж ми зможемо бігти, тому ми спочатку пройдемося через щось тривіальне та безглузде, щоб побачити, як саме працюють веб-компоненти.

Усе в цій публікації буде створювати ванільні веб-компоненти без будь-яких інструментів. Це означає, що код буде трохи шаблонним, але його слід відносно легко дотримуватися. Інструменти, як Освітлений or Трафарет призначені для створення веб-компонентів і можуть використовуватися для видалення більшої частини цього шаблону. Я закликаю вас перевірити їх! Але для цієї публікації я віддаю перевагу трохи більше шаблону в обмін на те, що не доведеться вводити та навчати іншу залежність.

Простий компонент лічильника

Давайте побудуємо класичний “Hello World” компонентів JavaScript: лічильник. Ми відобразимо значення та кнопку, яка збільшує це значення. Просто і нудно, але це дозволить нам розглянути найпростіший можливий веб-компонент.

Щоб створити веб-компонент, першим кроком є ​​створення класу JavaScript, який успадковується від HTMLElement:

class Counter extends HTMLElement {}

Останнім кроком є ​​реєстрація веб-компонента, але лише якщо ми його ще не зареєстрували:

if (!customElements.get("counter-wc")) { customElements.define("counter-wc", Counter);
}

І, звісно, ​​передати його:

<counter-wc></counter-wc>

І все між цим ми змушуємо веб-компонент робити те, що ми хочемо. Одним із поширених методів життєвого циклу є connectedCallback, який запускається, коли наш веб-компонент додається до DOM. Ми могли б використовувати цей метод для відображення будь-якого вмісту, який забажаємо. Пам’ятайте, що це клас JS, успадкований від HTMLElement, що означає наш this значенням є сам елемент веб-компонента з усіма звичайними методами маніпулювання DOM, які ви вже знаєте і любите.

Найпростіше, ми могли б зробити це:

class Counter extends HTMLElement { connectedCallback() { this.innerHTML = "<div style='color: green'>Hey</div>"; }
} if (!customElements.get("counter-wc")) { customElements.define("counter-wc", Counter);
}

…що буде працювати нормально.

Слово «привіт» зеленим кольором.
Створення взаємодіючих веб-компонентів, які працюють навіть із React

Додавання реального контенту

Давайте додамо корисний інтерактивний вміст. Нам потрібен а <span> для збереження поточного значення числа та a <button> для збільшення лічильника. Наразі ми створимо цей вміст у нашому конструкторі та додамо його, коли веб-компонент насправді знаходиться в DOM:

constructor() { super(); const container = document.createElement('div'); this.valSpan = document.createElement('span'); const increment = document.createElement('button'); increment.innerText = 'Increment'; increment.addEventListener('click', () => { this.#value = this.#currentValue + 1; }); container.appendChild(this.valSpan); container.appendChild(document.createElement('br')); container.appendChild(increment); this.container = container;
} connectedCallback() { this.appendChild(this.container); this.update();
}

Якщо ви справді вражені створенням DOM вручну, пам’ятайте, що ви можете налаштувати innerHTML, або навіть один раз створіть елемент шаблону як статичну властивість класу вашого веб-компонента, клонуйте його та вставте вміст для нових екземплярів веб-компонента. Напевно, є деякі інші варіанти, про які я не думаю, або ви завжди можете використовувати фреймворк веб-компонентів, наприклад Освітлений or Трафарет. Але для цієї публікації ми продовжимо робити це просто.

Продовжуємо, нам знадобиться настроювана властивість класу JavaScript з назвою value

#currentValue = 0; set #value(val) { this.#currentValue = val; this.update();
}

Це просто стандартна властивість класу з сетером, а також друга властивість для зберігання значення. Один цікавий поворот полягає в тому, що я використовую синтаксис властивості приватного класу JavaScript для цих значень. Це означає, що ніхто за межами нашого веб-компонента ніколи не може торкнутися цих значень. Це стандартний JavaScript це підтримується в усіх сучасних браузерах, тому не бійтеся ним користуватися.

Або сміливо телефонуйте _value якщо ви віддаєте перевагу. І, нарешті, наша update метод:

update() { this.valSpan.innerText = this.#currentValue;
}

Це працює!

Веб-компонент лічильника.
Створення взаємодіючих веб-компонентів, які працюють навіть із React

Очевидно, що це не той код, який ви хотіли б підтримувати в масштабі. Ось повна робочий приклад якщо ви хочете ближче подивитися. Як я вже говорив, такі інструменти, як Lit і Stencil, створені, щоб зробити це простіше.

Додавання додаткової функціональності

Ця публікація не є глибоким зануренням у веб-компоненти. Ми не будемо охоплювати всі API та життєві цикли; ми навіть не накриємо тіньові коріння або прорізи. На ці теми є нескінченний вміст. Моя мета тут — надати достатньо гідне вступ, щоб викликати певний інтерес, а також корисні вказівки щодо фактичного використання веб-компоненти з популярними фреймворками JavaScript, які ви вже знаєте і любите.

З цією метою давайте трохи покращимо наш веб-компонент лічильника. Нехай це прийме а color атрибут, щоб керувати кольором значення, яке відображається. І давайте також прийняти це increment властивості, тому споживачі цього веб-компонента можуть збільшити його на 2, 3, 4 за раз. І щоб стимулювати ці зміни стану, давайте використаємо наш новий лічильник у пісочниці Svelte — ми перейдемо до React невдовзі.

Ми почнемо з того самого веб-компонента, що й раніше, і додамо атрибут кольору. Щоб налаштувати наш веб-компонент для прийняття й відповіді на атрибут, ми додаємо статику observedAttributes властивість, яка повертає атрибути, які слухає наш веб-компонент.

static observedAttributes = ["color"];

Маючи це на місці, ми можемо додати a attributeChangedCallback метод життєвого циклу, який запускатиметься щоразу, коли будь-який з атрибутів, перерахованих у observedAttributes встановлені або оновлені.

attributeChangedCallback(name, oldValue, newValue) { if (name === "color") { this.update(); }
}

Зараз ми оновлюємо нашу update метод фактичного використання:

update() { this.valSpan.innerText = this._currentValue; this.valSpan.style.color = this.getAttribute("color") || "black";
}

Нарешті, давайте додамо нашу increment майно:

increment = 1;

Простий і скромний.

Використання компонента лічильника в Svelte

Давайте використаємо те, що ми щойно зробили. Ми перейдемо до нашого компонента програми Svelte і додамо щось на зразок цього:

<script> let color = "red";
</script> <style> main { text-align: center; }
</style> <main> <select bind:value={color}> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </select> <counter-wc color={color}></counter-wc>
</main>

І це працює! Наш лічильник відтворює, збільшує, а спадне меню оновлює колір. Як ви можете бачити, ми відображаємо атрибут color у нашому шаблоні Svelte, і, коли значення змінюється, Svelte справляється з процесом виклику setAttribute на нашому базовому екземплярі веб-компонента. Тут немає нічого особливого: це те саме, що він уже робить для атрибутів будь-який Елемент HTML.

З цим все стає трохи цікавим increment опора. Це є НЕ атрибут нашого веб-компонента; це опора класу веб-компонента. Це означає, що його потрібно встановити на екземплярі веб-компонента. Потерпіть, бо через деякий час все стане набагато простіше.

Спочатку ми додамо деякі змінні до нашого компонента Svelte:

let increment = 1;
let wcInstance;

Наша потужність компонента лічильника дозволить вам збільшити на 1 або на 2:

<button on:click={() => increment = 1}>Increment 1</button>
<button on:click={() => increment = 2}>Increment 2</button>

Але, теоретично, нам потрібно отримати фактичний екземпляр нашого веб-компонента. Це те саме, що ми завжди робимо, коли додаємо a ref з React. Зі Svelte це просто bind:this директива:

<counter-wc bind:this={wcInstance} color={color}></counter-wc>

Тепер у нашому шаблоні Svelte ми слухаємо зміни змінної приросту нашого компонента та встановлюємо базову властивість веб-компонента.

$: { if (wcInstance) { wcInstance.increment = increment; }
}

Ви можете перевірити це на цьому живому демо.

Ми, очевидно, не хочемо робити це для кожного веб-компонента або опори, яким нам потрібно керувати. Чи не було б добре, якби ми могли просто встановити increment прямо на нашому веб-компоненті, у розмітці, як ми зазвичай робимо для компонентних реквізитів, і маємо це, ви знаєте, просто робота? Іншими словами, було б добре, якби ми могли видалити всі випадки використання wcInstance і замість цього використовуйте цей простіший код:

<counter-wc increment={increment} color={color}></counter-wc>

Виявляється, можемо. Цей код працює; Svelte вирішує всю цю роботу за нас. Перевірте це в цій демонстрації. Це стандартна поведінка майже для всіх фреймворків JavaScript.

Чому я показав вам ручний спосіб налаштування параметра веб-компонента? Дві причини: корисно зрозуміти, як ці речі працюють, і хвилину тому я сказав, що це працює «майже» для всіх фреймворків JavaScript. Але є один фреймворк, який, на жаль, не підтримує налаштування параметрів веб-компонента, як ми щойно бачили.

React — це інший звір

Створення сумісних веб-компонентів, які навіть працюють із React PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.
Створення взаємодіючих веб-компонентів, які працюють навіть із React

Відреагувати. Найпопулярніший фреймворк JavaScript на планеті не підтримує базову взаємодію з веб-компонентами. Це добре відома проблема, властива лише React. Цікаво, що це насправді виправлено в експериментальній гілці React, але чомусь не було об’єднано з версією 18. Тим не менш, ми все ще можемо відстежувати його хід. І ви можете спробувати це самостійно за допомогою a демо.

Рішення, звичайно, полягає у використанні a ref, захопіть екземпляр веб-компонента та встановіть його вручну increment коли це значення змінюється. Це виглядає так:

import React, { useState, useRef, useEffect } from 'react';
import './counter-wc'; export default function App() { const [increment, setIncrement] = useState(1); const [color, setColor] = useState('red'); const wcRef = useRef(null); useEffect(() => { wcRef.current.increment = increment; }, [increment]); return ( <div> <div className="increment-container"> <button onClick={() => setIncrement(1)}>Increment by 1</button> <button onClick={() => setIncrement(2)}>Increment by 2</button> </div> <select value={color} onChange={(e) => setColor(e.target.value)}> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </select> <counter-wc ref={wcRef} increment={increment} color={color}></counter-wc> </div> );
}

Як ми вже обговорювали, кодування цього вручну для кожної властивості веб-компонента просто не масштабується. Але не все втрачено, тому що у нас є кілька варіантів.

Варіант 1. Використовуйте атрибути всюди

У нас є атрибути. Якщо ви натиснули демонстрацію React вище, increment опора не працювала, але колір змінився правильно. Хіба ми не можемо кодувати все за допомогою атрибутів? На жаль, ні. Значеннями атрибутів можуть бути лише рядки. Тут цього достатньо, і ми могли б зайти дещо далеко за допомогою такого підходу. Цифри як increment можна конвертувати в рядки та з них. Ми навіть можемо об’єкти у вигляді рядків або синтаксичних аналізів JSON. Але в кінцевому підсумку нам потрібно буде передати функцію у веб-компонент, і в цей момент у нас не буде можливостей.

Варіант 2: загорніть його

Є стара приказка, що ви можете вирішити будь-яку проблему в інформатиці, додавши рівень опосередкованості (крім проблеми занадто великої кількості рівнів опосередкованості). Код для встановлення цих реквізитів досить передбачуваний і простий. А якщо ми сховаємо його в бібліотеці? Розумні люди, які стоять за літ мати одне рішення. Ця бібліотека створює для вас новий компонент React після того, як ви надасте йому веб-компонент і перерахуєте необхідні властивості. Хоча я розумний, я не прихильник такого підходу.

Замість того, щоб відображати веб-компоненти один до одного зі створеними вручну компонентами React, я віддаю перевагу просто один Компонент React, який ми передаємо нашому веб-компоненту назва тегу до (counter-wc у нашому випадку) — разом з усіма атрибутами та властивостями — і щоб цей компонент відображав наш веб-компонент, додайте файл ref, потім з’ясуйте, що таке опора, а що атрибут. Це ідеальне рішення, на мою думку. Я не знаю бібліотеки, яка б це робила, але створити її має бути просто. Давайте спробуємо!

Це використання ми шукаємо:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

wcTag ім'я тегу веб-компонента; решта - це властивості та атрибути, які ми хочемо передати.

Ось як виглядає моя реалізація:

import React, { createElement, useRef, useLayoutEffect, memo } from 'react'; const _WcWrapper = (props) => { const { wcTag, children, ...restProps } = props; const wcRef = useRef(null); useLayoutEffect(() => { const wc = wcRef.current; for (const [key, value] of Object.entries(restProps)) { if (key in wc) { if (wc[key] !== value) { wc[key] = value; } } else { if (wc.getAttribute(key) !== value) { wc.setAttribute(key, value); } } } }); return createElement(wcTag, { ref: wcRef });
}; export const WcWrapper = memo(_WcWrapper);

Найцікавіший рядок в кінці:

return createElement(wcTag, { ref: wcRef });

Ось як ми створюємо елемент у React з динамічною назвою. Насправді, це те, у що React зазвичай транспілює JSX. Усі наші div конвертуються в createElement("div") дзвінки. Зазвичай нам не потрібно безпосередньо викликати цей API, але він є там, коли нам це потрібно.

Крім цього, ми хочемо запустити ефект макета та прокрутити кожну опору, яку ми передали нашому компоненту. Ми переглядаємо всі їх і перевіряємо, чи є це властивість з in перевірте, що перевіряє об’єкт екземпляра веб-компонента, а також його ланцюжок прототипів, який ловить будь-які гетери/налаштування, які потрапляють на прототип класу. Якщо такої властивості не існує, вважається, що це атрибут. У будь-якому випадку ми встановлюємо його, лише якщо значення дійсно змінилося.

Якщо вам цікаво, чому ми використовуємо useLayoutEffect замість useEffect, тому що ми хочемо негайно запустити ці оновлення до того, як наш вміст буде відтворено. Також зверніть увагу, що у нас немає масиву залежностей useLayoutEffect; це означає, що ми хочемо запустити це оновлення кожен рендер. Це може бути ризиковано, оскільки React має тенденцію до повторного відтворення багато. Я покращую це, загортаючи все React.memo. Це, по суті, сучасна версія React.PureComponent, що означає, що компонент буде повторно відтворюватися лише в тому випадку, якщо будь-який із його фактичних реквізитів змінився — і він перевіряє, чи сталося це за допомогою простої перевірки рівності.

Єдиний ризик тут полягає в тому, що якщо ви передаєте об’єкт, який ви мутуєте безпосередньо без повторного призначення, ви не побачите оновлень. Але це дуже не рекомендується, особливо в спільноті React, тому я б не турбувався про це.

Перш ніж рухатися далі, я хотів би зазначити ще одну річ. Ви можете бути не задоволені тим, як виглядає використання. Знову ж таки, цей компонент використовується так:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

Зокрема, вам може не сподобатися передача назви тегу веб-компонента до <WcWrapper> компонент і віддати перевагу замість цього @lit-labs/react пакет вище, який створює новий індивідуальний компонент React для кожного веб-компонента. Це цілком справедливо, і я закликаю вас використовувати те, що вам найбільше зручно. Але для мене одна перевага цього підходу полягає в тому, що це легко видаляти. Якщо якимось дивом React об’єднає належну обробку веб-компонентів зі своєї експериментальної гілки в main завтра ви зможете змінити наведений вище код із цього:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

…до цього:

<counter-wc ref={wcRef} increment={increment} color={color} />

Можливо, ви навіть можете написати один кодовий мод, щоб робити це скрізь, а потім видалити <WcWrapper> взагалі. Насправді, подряпайте це: глобальний пошук і заміна на регулярний вираз, ймовірно, спрацює.

Впровадження

Я знаю, здається, що потрібна була дорога, щоб потрапити сюди. Якщо ви пам’ятаєте, нашою початковою метою було взяти код попереднього перегляду зображення, який ми розглядали в моєму загрузка повідомлення, і перемістіть його до веб-компонента, щоб його можна було використовувати в будь-якій структурі JavaScript. Відсутність належного взаємодії в React додала багато деталей до суміші. Але тепер, коли ми добре знаємо, як створити веб-компонент і використовувати його, реалізація буде майже невдалою.

Я скину тут весь веб-компонент і назву деякі цікаві моменти. Якщо ви хочете побачити це в дії, ось a робоча демонстрація. Він перемикатиметься між трьома моїми улюбленими книгами на трьох моїх улюблених мовах програмування. URL-адреса для кожної книги буде унікальною кожного разу, тому ви можете побачити попередній перегляд, хоча вам, ймовірно, захочеться регулювати параметри на вкладці DevTools Network, щоб дійсно побачити, що відбувається.

Переглянути весь код
class BookCover extends HTMLElement { static observedAttributes = ['url']; attributeChangedCallback(name, oldValue, newValue) { if (name === 'url') { this.createMainImage(newValue); } } set preview(val) { this.previewEl = this.createPreview(val); this.render(); } createPreview(val) { if (typeof val === 'string') { return base64Preview(val); } else { return blurHashPreview(val); } } createMainImage(url) { this.loaded = false; const img = document.createElement('img'); img.alt = 'Book cover'; img.addEventListener('load', () =&gt; { if (img === this.imageEl) { this.loaded = true; this.render(); } }); img.src = url; this.imageEl = img; } connectedCallback() { this.render(); } render() { const elementMaybe = this.loaded ? this.imageEl : this.previewEl; syncSingleChild(this, elementMaybe); }
}

Спочатку ми реєструємо атрибут, який нас цікавить, і реагуємо, коли він змінюється:

static observedAttributes = ['url']; attributeChangedCallback(name, oldValue, newValue) { if (name === 'url') { this.createMainImage(newValue); }
}

Це призводить до створення нашого компонента зображення, який відображатиметься лише після завантаження:

createMainImage(url) { this.loaded = false; const img = document.createElement('img'); img.alt = 'Book cover'; img.addEventListener('load', () => { if (img === this.imageEl) { this.loaded = true; this.render(); } }); img.src = url; this.imageEl = img;
}

Далі ми маємо властивість попереднього перегляду, яка може бути або нашим рядком попереднього перегляду base64, або нашим blurhash пакет:

set preview(val) { this.previewEl = this.createPreview(val); this.render();
} createPreview(val) { if (typeof val === 'string') { return base64Preview(val); } else { return blurHashPreview(val); }
}

Це стосується будь-якої допоміжної функції, яка нам потрібна:

function base64Preview(val) { const img = document.createElement('img'); img.src = val; return img;
} function blurHashPreview(preview) { const canvasEl = document.createElement('canvas'); const { w: width, h: height } = preview; canvasEl.width = width; canvasEl.height = height; const pixels = decode(preview.blurhash, width, height); const ctx = canvasEl.getContext('2d'); const imageData = ctx.createImageData(width, height); imageData.data.set(pixels); ctx.putImageData(imageData, 0, 0); return canvasEl;
}

І, нарешті, наша render метод:

connectedCallback() { this.render();
} render() { const elementMaybe = this.loaded ? this.imageEl : this.previewEl; syncSingleChild(this, elementMaybe);
}

І кілька допоміжних методів, щоб зв'язати все разом:

export function syncSingleChild(container, child) { const currentChild = container.firstElementChild; if (currentChild !== child) { clearContainer(container); if (child) { container.appendChild(child); } }
} export function clearContainer(el) { let child; while ((child = el.firstElementChild)) { el.removeChild(child); }
}

Це трохи більше шаблону, ніж нам знадобиться, якщо ми побудуємо це у фреймворку, але перевагою є те, що ми можемо повторно використовувати це в будь-якому фреймворку, який забажаємо — хоча React наразі знадобиться обгортка, як ми обговорювали .

Обривки

Я вже згадував обгортку Lit React. Але якщо ви використовуєте Stencil, він насправді підтримує a окремий вихідний конвеєр тільки для React. І хороші люди в Microsoft також створив щось подібне до обгортки Lit, приєднаний до бібліотеки веб-компонентів Fast.

Як я вже згадував, усі фреймворки без імені React оброблятимуть для вас налаштування властивостей веб-компонента. Просто зверніть увагу, що деякі з них мають особливі особливості синтаксису. Наприклад, із Solid.js, <your-wc value={12}> завжди припускає це value є властивістю, яку можна змінити за допомогою an attr префікс, як <your-wc attr:value={12}>.

Підводячи підсумок

Веб-компоненти є цікавою, часто недостатньо використовуваною частиною ландшафту веб-розробки. Вони можуть допомогти зменшити вашу залежність від будь-якої окремої платформи JavaScript, керуючи вашим інтерфейсом або компонентами «листка». Хоча створення таких веб-компонентів — на відміну від компонентів Svelte або React — не буде таким ергономічним, перевагою є те, що їх можна буде використовувати багаторазово.


Створення взаємодіючих веб-компонентів, які працюють навіть із React спочатку опубліковано на CSS-трюки. Ти повинен отримати інформаційний бюлетень.

Часова мітка:

Більше від CSS-хитрощі