Ось готовий урок, створений у стилі CS50, де ми розберемо тему директив на прикладі Angular (оскільки саме в цьому фреймворку концепція "Директив" реалізована найбільш академічно та наочно).
🏛 CS50: Директиви — Магія управління DOM-деревом
Привіт, друзі! Мене звати [Твоє Ім'я], і це CS50... тобто, наш урок з архітектури веб-додатків!
Сьогодні ми поговоримо про річ, яка перетворює статичний HTML на щось живе, що дихає і реагує на ваші дії. Ми поговоримо про Директиви.
1. 🔥 Вступ: Чому без цього ніяк?
Уявіть собі ситуацію. Ви будуєте розумний будинок. У вас є звичайна лампочка. Щоб вона загорілася, коли ви заходите в кімнату, вам потрібно підійти до вимикача і фізично натиснути його.
У світі JavaScript це виглядало б так:
1. Знайти елемент у DOM (document.getElementById).
2. Перевірити умову.
3. Змінити йому стиль (element.style.display = 'block').
А тепер уявіть, що у вас 100 лампочок. І 50 кімнат. Ви будете бігати й клацати кожним вимикачем вручну? Ні.
Ви хочете наклеїти на лампочку стікер із написом: "Вмикайся, якщо хтось є в кімнаті" — і нехай вона сама розбирається, як це зробити.
Питання до вас: Чи не було б круто, якби ми могли навчити HTML "думати"? Щоб ми могли написати в коді <div *if="userIsAdmin">, і блок з'являвся б тільки для адміна, без жодного рядка document.querySelector?
Саме це і роблять Директиви. Це інструкції для браузера: "Гей, коли бачиш цей елемент, зроби з ним дещо особливе".
2. 🧠 Теоретична база (Що "під капотом"?)
Давайте спростимо. Якщо Компонент (Component) — це іменник (це "Віджет погоди", це "Картка товару"), то Директива — це дієслово або прикметник.
Директива не має власного шаблону (HTML). Вона "паразитує" на існуючому елементі та змінює його поведінку.
Є два головні типи директив, які вам треба розрізняти (якщо ви це зрозумієте, ви зрозуміли 80% теми):
🅰️ Структурні директиви (Structural Directives)
- Аналогія: Будівельник або фокусник.
- Що роблять: Вони фізично додають або видаляють елементи з DOM-дерева.
- Як впізнати: Зазвичай починаються із зірочки
*(наприклад,*ngIf,*ngFor). - Важливо: Якщо умова
false, елемент не просто ховається (CSShidden) — він зникає з пам'яті. Його не існує.
🅱️ Атрибутні директиви (Attribute Directives)
- Аналогія: Маляр або стиліст.
- Що роблять: Вони змінюють зовнішній вигляд або поведінку вже існуючого елемента.
- Як впізнати: Виглядають як звичайні атрибути HTML, часто у квадратних дужках
[](наприклад,[ngStyle],[ngClass]). - Важливо: Елемент залишається на місці, просто стає зеленим, починає миготіти або слухати кліки.
3. 🧪 Приклади (Show me the code!)
Давайте подивимось, як це виглядає в коді (на прикладі Angular, але логіка схожа у Vue/React).
Рівень 1: Вбудовані директиви (Те, що вже є в коробці)
У нас є змінна isLoggedIn = false.
<!-- Структурна директива *ngIf -->
<div *ngIf="isLoggedIn">
Ласкаво просимо, Користувачу!
</div>
<div *ngIf="!isLoggedIn">
Будь ласка, увійдіть.
</div>
👉 Що тут відбувається? Angular дивиться на isLoggedIn. Якщо це false, перший div навіть не рендериться. Його немає в HTML коді сторінки.
Рівень 2: Списки (Loop)
У нас є масив: users = ['Оля', 'Петро', 'Марія'].
<!-- Структурна директива *ngFor -->
<ul>
<li *ngFor="let user of users">
{{ user }}
</li>
</ul>
👉 Очікування: Що ми побачимо на екрані?
Правильно: Три пункти списку. Якщо ми додамо "Івана" в масив, Angular автоматично створить четвертий <li>.
Рівень 3: Користувацька директива (Створюємо свою магію)
А тепер уявіть: ви хочете, щоб при наведенні мишки на текст він ставав жовтим. Вбудованої директиви *MakeItYellow немає.
Ми створюємо свою директиву appHighlight.
// highlight.directive.ts
@Directive({
selector: '[appHighlight]' // Це ім'я, яке ми шукаємо в HTML
})
export class HighlightDirective {
constructor(private el: ElementRef) {}
// Слухаємо подію 'mouseenter' (наведення миші)
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
// Слухаємо, коли миша йде геть
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
private highlight(color: string) {
// Прямий доступ до DOM (безпечно, бо через обгортку)
this.el.nativeElement.style.backgroundColor = color;
}
}
Використання в HTML:
<p appHighlight>Наведи на мене мишку!</p>
👉 Як це працює?
1. Angular бачить атрибут appHighlight.
2. Створює екземпляр класу HighlightDirective.
3. Передає йому посилання на цей <p> (через ElementRef).
4. Директива починає "слухати" події миші на цьому параграфі.
4. 🛠 Практична частина
Час забруднити руки кодом! Виконайте ці завдання (подумки або у редакторі):
- 🔹 Рефакторинг: У вас є 5 однакових карток товарів, прописаних вручну в HTML. Як використати
*ngFor, щоб скоротити код до 1 блоку? - 🔹 Логічна пастка: Використайте
*ngIf, щоб приховати кнопку "Купити", якщо товару немає на складі (quantity === 0). - 🔹 Своя директива (Level Up): Напишіть (псевдокодом) директиву
appPasswordToggle.- Задача: При кліку на іконку ока, вона має знаходити сусідній
inputі змінювати його тип зpasswordнаtextі навпаки.
- Задача: При кліку на іконку ока, вона має знаходити сусідній
- 🔹 Кейс "А що, якщо...": Ви застосували директиву
*ngIfі директиву*ngForна одному й тому ж елементі.- Питання: Чому це погана ідея і викличе помилку? (Підказка: як браузер зрозуміє, що робити першим — створювати список чи перевіряти умову показу?)
- 🔹 Бізнес-задача: Менеджер просить: "Я хочу, щоб усі ціни, вищі за 1000 грн, автоматично підсвічувались червоним". Яку директиву ви створите — структурну чи атрибутну?
5. 💡 Мислення як у розробника
Послухайте уважно, це відрізнить вас від новачків.
❌ Новачок думає:
"Мені треба змінити колір кнопки. Я піду в компонент, напишу функцію changeColor(), знайду кнопку через ID..."
✅ Сеньйор думає: "Зміна кольору при наведенні — це поведінка, а не бізнес-логіка компонента. Цю логіку я, можливо, захочу використати ще на 20 інших кнопках. Я винесу це в окрему Директиву".
Типові помилки:
1. Прямий доступ до DOM в компоненті. Ніколи не пишіть document.getElementById всередині Angular/React компонента, якщо це можна зробити директивою. Це ламає абстракцію.
2. Плутанина типів. Спроба використати структурну директиву як атрибутну (очікувати, що *ngIf просто сховає елемент через CSS, а не знищить його). Це може призвести до втрати даних, введених користувачем у форму, яка "зникла".
6. 🧩 Підсумок
Отже, що ми сьогодні вивчили:
- Директиви — це спосіб навчити HTML новим трюкам.
- Структурні (*) — змінюють структуру DOM (додають/видаляють). Як будівельники.
- Атрибутні ([]) — змінюють вигляд/поведінку. Як декоратори.
- Користувацькі — коли вбудованих не вистачає, ми пишемо свої, щоб дотримуватися принципу DRY (Don't Repeat Yourself).
Що ви тепер вмієте? Ви можете не просто виводити дані, а керувати тим, як і коли вони відображаються, причому робити це елегантно, використовуючи декларативний стиль.
🔜 Далі в курсі: Ми навчилися керувати елементами. Але як передавати дані між ними? На наступному уроці ми розберемо Input/Output та Сервіси — кровоносну систему нашого додатку.
А поки що... це був CS50! 🖐🎤 (кидає мікрофон)