Haunted — это современная библиотека для создания веб-компонентов на базе Web Components и реактивного подхода, использующая Hooks, аналогичные React. Одним из ключевых аспектов работы с Haunted является корректное управление атрибутами и свойствами компонентов, особенно при построении динамических шаблонов.
В Web Components и, следовательно, в Haunted существует важное различие между атрибутами (attributes) и свойствами (properties):
Атрибуты — это строки, которые определяются в
HTML-разметке и доступны через
getAttribute/setAttribute. Они сериализуются в
HTML, поэтому любые нестроковые значения должны быть преобразованы.
<my-component title="Пример"></my-component>
В Jav * aScript:
const title = element.getAttribute('title'); // "Пример"Свойства — это реальные свойства объекта компонента, которые могут быть любого типа (объекты, массивы, функции). Они не сериализуются автоматически в HTML.
element.data = { id: 1, name: 'Тест' };В Haunted важно различать, когда нужно использовать атрибут (для простых строковых данных и взаимодействия с HTML) и свойство (для сложных данных и реактивного рендеринга).
Haunted позволяет реактивно отслеживать изменения свойств
компонента через механизм @property (через
Lit-like API) или с использованием хуков. Для обычных функциональных
компонентов управление свойствами происходит через параметры
функции:
import { html, component } from 'haunted';
function MyComponent({ title, count }) {
return html`
<h1>${title}</h1>
<p>Количество: ${count}</p>
`;
}
customElements.define('my-component', component(MyComponent));
В этом примере title и count автоматически
становятся свойствами компонента, которые можно
передавать из HTML или JavaScript.
Haunted использует синтаксис lit-html, поэтому для
вставки динамических значений в атрибуты применяются
${}. Важно помнить, что это работает по-разному для
строковых атрибутов и свойств объекта:
html`<input type="text" .value=${value} placeholder=${placeholder} />`
placeholder=${placeholder} — устанавливает
атрибут placeholder, который отображается в HTML..value=${value} — устанавливает
свойство value объекта input,
что критично для реактивного обновления значения поля.Префикс . указывает Haunted (и Lit) на
то, что нужно работать с свойством элемента, а не с атрибутом.
Haunted автоматически реагирует на изменения свойств компонента, если они передаются как параметры функции. Любое изменение этих свойств вызывает повторный рендер компонента:
function Counter({ count }) {
return html`<p>Счетчик: ${count}</p>`;
}
const counterElement = document.createElement('my-counter');
counterElement.count = 10;
document.body.appendChild(counterElement);
setTimeout(() => {
counterElement.count = 15; // Автоматический ререндер
}, 1000);
Если необходимо обновлять атрибуты напрямую, лучше использовать
reflect в сочетании с кастомным элементом для синхронизации
свойства и атрибута:
class ReflectComponent extends HTMLElement {
static get observedAttributes() { return ['name']; }
get name() { return this._name; }
set name(val) {
this._name = val;
this.setAttribute('name', val); // отражение свойства в атрибут
}
attributeChangedCallback(attr, oldVal, newVal) {
if (attr === 'name') this._name = newVal;
}
}
Boolean-атрибуты требуют отдельного подхода, так как их присутствие в
HTML означает true, а отсутствие — false. В
Haunted рекомендуется использовать привязку к свойству:
html`<button ?disabled=${isDisabled}>Нажми меня</button>`
?disabled=${isDisabled} — синтаксис для
boolean-атрибутов. Если isDisabled истинно, атрибут
disabled добавляется, если ложь — удаляется.Свойства сложных типов (объекты, массивы) передаются как свойства компонента, а не атрибуты. Атрибуты поддерживают только строковые значения. Пример реактивного объекта:
function UserCard({ user }) {
return html`
<div>
<h2>${user.name}</h2>
<p>Email: ${user.email}</p>
</div>
`;
}
const card = document.createElement('user-card');
card.user = { name: 'Иван', email: 'ivan@mail.com' };
document.body.appendChild(card);
Любое обновление объекта user через присваивание нового
значения вызовет повторный рендер.
При работе со свойствами часто требуется синхронизация с событиями DOM:
html`<input .value=${value} @input=${e => value = e.target.value} />`
.value=${value} — связывает свойство input с переменной
value.@input=${...} — обрабатывает событие изменения. Это
позволяет организовать двустороннюю привязку данных.?attr=${value}.. в шаблонах гарантирует установку свойства
DOM-элемента.Корректное управление атрибутами и свойствами обеспечивает не только реактивность, но и правильную интеграцию компонентов с другими элементами страницы и нативными API браузера.