Открытый и закрытый режимы
📅
Два режима работы
Shadow DOM поддерживает два режима доступа:
1. Открытый режим (open)
Доступ извне возможен через element.shadowRoot:
// Создание
const element = document.createElement('div');
element.attachShadow({ mode: 'open' });
// Доступ извне
console.log(element.shadowRoot); // Доступен
element.shadowRoot.innerHTML = '<p>Контент</p>';
2. Закрытый режим (closed)
Доступ извне невозможен, element.shadowRoot возвращает null:
// Создание
const element = document.createElement('div');
element.attachShadow({ mode: 'closed' });
// Доступ извне
console.log(element.shadowRoot); // null
Сравнение режимов
| Характеристика | Открытый режим | Закрытый режим |
|---|---|---|
| Доступ из JavaScript | ✅ Через element.shadowRoot |
❌ Всегда null |
| Безопасность | 🔓 Ниже | 🔒 Выше |
| Гибкость | ✅ Высокая | ❌ Ограниченная |
| Использование | 95% случаев | 5% специальных кейсов |
Практические примеры
Открытый режим (рекомендуется)
class OpenComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>:host { display: block; }</style>
<p>Открытый компонент</p>
`;
}
}
// Доступ извне
const comp = document.querySelector('open-component');
comp.shadowRoot.querySelector('p').style.color = 'red';
Закрытый режим (редкие случаи)
class ClosedComponent extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: 'closed' });
this._shadowRoot.innerHTML = `
<style>:host { display: block; }</style>
<p>Закрытый компонент</p>
`;
}
// Специальный метод для доступа
getShadowRoot() {
return this._shadowRoot;
}
}
// Доступ только через API
const comp = document.querySelector('closed-component');
comp.getShadowRoot().querySelector('p').style.color = 'blue';
Когда что использовать
✅ Открытый режим используйте для:
- Большинства UI-компонентов
- Библиотек и фреймворков
- Компонентов, требующих кастомизации
- Ситуаций, когда нужен доступ к внутренностям
⚠️ Закрытый режим используйте для:
- Критически важных компонентов
- Защиты внутренней логики
- Компонентов с чувствительными данными
- Strict API-интерфейсов
Особенности закрытого режима
Ограничение доступа
class SecureComponent extends HTMLElement {
constructor() {
super();
this._shadow = this.attachShadow({ mode: 'closed' });
this._shadow.innerHTML = `<p>Секретный контент</p>`;
}
// Контролируемый API
updateContent(text) {
this._shadow.querySelector('p').textContent = text;
}
}
// Нельзя получить прямой доступ
const secure = document.querySelector('secure-component');
secure.shadowRoot; // null
secure.updateContent('Новый текст'); // Через API
Обход ограничений (не рекомендуется)
// Нарушение инкапсуляции (антипаттерн!)
const element = document.querySelector('closed-component');
const shadow = element._shadowRoot; // Доступ к приватному полю
Декларативный подход
Открытый режим
<my-element>
<template shadowrootmode="open">
<p>Открытый декларативный Shadow DOM</p>
</template>
</my-element>
Закрытый режим
<my-element>
<template shadowrootmode="closed">
<p>Закрытый декларативный Shadow DOM</p>
</template>
</my-element>
Best Practices
- Используйте открытый режим по умолчанию
- Закрытый режим только для особых случаев
- Не полагайтесь на приватные поля для обхода closed mode
- Документируйте API для закрытых компонентов
- Тестируйте оба режима в целевых браузерах
Браузерная поддержка
Оба режима поддерживаются во всех современных браузерах:
- Chrome 53+ ✅
- Firefox 63+ ✅
- Safari 10.1+ ✅
- Edge 79+ ✅