Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке прив'язки атрибутів у Vue?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Прив'язка атрибутів** (attribute binding) у Vue - директива `v-bind` або скорочення `:` підключає HTML-атрибути та пропси до реактивних даних, оновлюючи DOM автоматично. ```html <img :src="imageUrl" :alt="imageAlt" /> <button :disabled="isSubmitting || null">Submit</button> <div v-bind="{ id: itemId, class: itemClass }"></div> ``` **Головне:** без `:` Vue сприймає значення як звичайний рядок, а не змінну.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Прив'язка атрибутів** (attribute binding) у Vue використовує директиву `v-bind` або скорочення `:`, щоб підключити HTML-атрибути та пропси компонентів до реактивних даних. ## Теорія ### TL;DR - `v-bind:href="url"` і `:href="url"` - одне й те саме; `:` є стандартним скороченням - На відміну від статичного `href="..."`, прив'язаний атрибут оновлюється в DOM автоматично при зміні даних - Використовуй `:`, якщо значення береться з `data`, `props` або виразу; в інших випадках пиши значення напряму - Прив'язка `null` або `undefined` повністю видаляє атрибут з DOM - Прив'язка `:disabled="false"` все одно вимикає кнопку, бо браузер вважає будь-який непорожній рядок truthy ### Короткий приклад ```html <template> <!-- Статично: завжди один і той самий рядок --> <a href="https://example.com">Статичне</a> <!-- Прив'язка: оновлюється при зміні userProfileUrl --> <a :href="userProfileUrl">Профіль</a> <button @click="updateUrl">Змінити URL</button> </template> <script> export default { data() { return { userProfileUrl: 'https://example.com/profile/1' }; }, methods: { updateUrl() { this.userProfileUrl = 'https://example.com/profile/2'; // href оновлюється в DOM автоматично, без ручних DOM-викликів } } }; </script> ``` Прив'язаний лінк одразу відображає нове значення. Статичний не змінюється ніколи. ### Статичні та динамічні атрибути Статичні атрибути, як `href="static.com"`, фіксуються в DOM при рендері. Vue їх більше не відстежує. Прив'язки на зразок `:href="url"` створюють реактивне з'єднання: система реактивності Vue (у Vue 3 базується на Proxy) стежить за `url`, і коли значення змінюється, планувальник ставить патч у чергу, який оновлює лише цей атрибут через virtual DOM. Повного перерендеру не відбувається. Поширена пастка: запис `<button disabled="isLoading">` замість `:disabled="isLoading"`. Без `:` Vue сприймає `"isLoading"` як звичайний рядок, а не змінну. Кнопка вимкнена завжди, незалежно від даних. ### Коли використовувати - Значення фіксоване і відоме при написанні коду: пиши напряму (`href="mailto:hi@example.com"`) - Значення береться з `data` або `props`: `:src="imageUrl"` - Умовна логіка: `:disabled="!isValid"` - Стиль з умовою: `:style="{ color: isError ? 'red' : 'green' }"` - Передача даних у дочірній компонент: `<MyButton :count="items.length">` - Розподіл кількох атрибутів одразу: `<div v-bind="{ id: docId, class: docClass }">` ### Як Vue обробляє прив'язки всередині Компілятор шаблонів перетворює `:href="url"` на виклик рендер-функції: `h('a', { href: _ctx.url })`. При монтуванні та оновленнях Proxy перехоплює запис у `url`, ставить завдання в чергу планувальника, і `patch` викликає `setAttribute` на DOM-вузлі. Змінюється лише цей один атрибут. ### Типові помилки **Прив'язка `null` або `undefined` без запасного значення:** ```html <!-- Неправильно: avatarUrl=undefined → src="" → 404 --> <img :src="avatarUrl" /> <!-- Правильно: запасне значення --> <img :src="avatarUrl || '/default-avatar.png'" /> ``` Якщо значення може бути відсутнім, додавай fallback або охороняй через `v-if="avatarUrl"`. **Булеві атрибути і рядок `"false"`:** ```html <!-- Неправильно: isDisabled=false → disabled="false" → кнопка вимкнена --> <button :disabled="isDisabled">Go</button> <!-- Правильно: null видаляє атрибут --> <button :disabled="isDisabled || null">Go</button> ``` Браузер вважає будь-який непорожній рядок truthy для булевих атрибутів. Передай `null`, щоб атрибут зник і кнопка стала активною. **Клас без умови:** ```html <!-- Неправильно: клас "active" присутній завжди --> <div :class="'active'">...</div> <!-- Правильно: об'єктний синтаксис для умовних класів --> <div :class="{ active: isActive }">...</div> ``` **Об'єктний літерал як один атрибут:** ```html <!-- Неправильно: об'єкт не є валідним значенням одного атрибута --> <div :data="{ id: user.id }">...</div> <!-- Правильно: окремий data-атрибут --> <div :data-id="user.id">...</div> ``` ### Де зустрічається в реальних проектах - Vuetify: `:color="themeColor"` на кнопках для динамічної теми - Quasar: `:dense="isMobile"` на списках для адаптивного вигляду - Nuxt з i18n: `:to="localePath('/cart')"` для локалізованих маршрутів - Element Plus: `:model-value="searchQuery"` на полях форм - Pinia: `:items="cartStore.items"` у компонентах кошика ### Можливі питання на співбесіді **Q:** Яка різниця між `:disabled="false"` і відсутністю атрибута `disabled`? **A:** `:disabled="false"` встановлює `disabled="false"` в HTML. Браузер вважає будь-який непорожній рядок truthy для булевих атрибутів, тому кнопка залишається вимкненою. Щоб увімкнути її, використовуй `:disabled="null"` або просто прибери атрибут. **Q:** Як Vue поводиться з `undefined` і `null` у прив'язках? **A:** Обидва видаляють атрибут у Vue 3. У Vue 2 `null` міг відрендеритись як порожній рядок. Для необов'язкових атрибутів надійніший патерн - `value || undefined`. **Q:** Як прив'язати кілька атрибутів одночасно? **A:** Використовуй `v-bind` з об'єктом: `<div v-bind="{ id: docId, class: docClass }">`. Vue розподіляє всі ключі як окремі атрибути на елементі. **Q:** Чому в Nuxt SSR виникають помилки гідратації при прив'язках? **A:** Сервер рендерить з початковими статичними даними, а клієнт гідратує з реактивним станом. Якщо ці значення відрізняються в момент монтування, Vue видає помилку гідратації. Вирішення: `useAsyncData` для спільного стану або `v-if="mounted"` навколо елемента. ## Приклади ### Базовий: зображення з динамічним src ```html <template> <img :src="catImage" :alt="`Cat ${catId}`" /> <button @click="nextCat">Наступне</button> </template> <script> export default { data() { return { catId: 1, catImage: 'https://example.com/cat1.jpg' }; }, methods: { nextCat() { this.catId++; this.catImage = `https://example.com/cat${this.catId}.jpg`; // src та alt оновлюються синхронно, без маніпуляцій з DOM } } }; </script> ``` `:src` і `:alt` реагують одночасно при зміні `catId`. Браузер перезавантажує зображення, бо отримує нове значення `src`. ### Середній рівень: форма входу з керуванням через стан ```html <template> <form @submit.prevent="login"> <input :value="email" @input="email = $event.target.value" placeholder="email@example.com" required /> <button :disabled="isSubmitting || !email.includes('@')"> {{ isSubmitting ? 'Входимо...' : 'Увійти' }} </button> </form> </template> <script> export default { data() { return { email: '', isSubmitting: false }; }, methods: { async login() { this.isSubmitting = true; await new Promise(r => setTimeout(r, 1000)); // імітація API-запиту this.isSubmitting = false; // кнопка повертається в активний стан автоматично } } }; </script> ``` Вираз у `:disabled` одразу покриває дві умови: невалідний email і запит у процесі. Жодного `document.querySelector`. Цей патерн зустрічається майже в кожній Vue-формі на продакшені.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.