Работа с атрибутами и свойствами
📅
Разница между атрибутами и свойствами
Атрибуты (HTML)
<user-card name="John" age="25" active></user-card>
Свойства (JavaScript)
const card = document.querySelector('user-card');
card.name = 'John'; // Свойство
card.age = 25; // Свойство
card.active = true; // Свойство
Отслеживание изменений атрибутов
Статический метод observedAttributes
static get observedAttributes() {
return ['name', 'age', 'status', 'disabled'];
}
Метод attributeChangedCallback
attributeChangedCallback(name, oldValue, newValue) {
console.log(`Атрибут ${name} изменился: ${oldValue} → ${newValue}`);
switch (name) {
case 'name':
this.handleNameChange(newValue);
break;
case 'age':
this.handleAgeChange(parseInt(newValue));
break;
case 'disabled':
this.handleDisabledChange(newValue !== null);
break;
}
}
Синхронизация атрибутов и свойств
Геттеры и сеттеры
class UserCard extends HTMLElement {
get name() {
return this.getAttribute('name');
}
set name(value) {
if (value) {
this.setAttribute('name', value);
} else {
this.removeAttribute('name');
}
}
get age() {
return parseInt(this.getAttribute('age')) || 0;
}
set age(value) {
this.setAttribute('age', value.toString());
}
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(value) {
if (value) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
}
}
Валидация данных
Проверка значений
set age(value) {
const age = parseInt(value);
if (age >= 0 && age <= 150) {
this.setAttribute('age', age.toString());
} else {
console.error('Invalid age value');
}
}
set name(value) {
if (typeof value === 'string' && value.length > 0) {
this.setAttribute('name', value);
}
}
Булевы атрибуты
Правильная обработка
get active() {
return this.hasAttribute('active');
}
set active(value) {
if (value) {
this.setAttribute('active', '');
} else {
this.removeAttribute('active');
}
}
// Использование
element.active = true; // Добавляет атрибут
element.active = false; // Удаляет атрибут
Сложные данные
JSON в атрибутах
// Запись
set data(value) {
this.setAttribute('data', JSON.stringify(value));
}
// Чтение
get data() {
try {
return JSON.parse(this.getAttribute('data') || '{}');
} catch {
return {};
}
}
// Использование
element.data = { id: 1, role: 'admin' };
console.log(element.data.id); // 1
Производительность
Оптимизация рендеринга
attributeChangedCallback(name, oldValue, newValue) {
// Не рендерить если значение не изменилось
if (oldValue === newValue) return;
// Дебаунс для частых изменений
clearTimeout(this.renderTimeout);
this.renderTimeout = setTimeout(() => {
this.render();
}, 50);
}
Best Practices
- Всегда валидируйте данные перед установкой
- Используйте observedAttributes для отслеживаемых атрибутов
- Синхронизируйте атрибуты и свойства
- Избегайте частых обновлений DOM в attributeChangedCallback
- Используйте соответствующие типы для разных данных