У розробці веб-додатків часто виникає потреба створення адаптивного дизайну, який би автоматично адаптувався під різні розміри екранів. Використання фреймворку Nuxt.js дозволяє значно спростити цей процес завдяки системі макетів (layouts). Однак, можуть виникати ситуації, коли необхідно динамічно змінювати макет залежно від поточного розміру вікна переглядача, що не завжди виявляється тривіальним завданням.
Розглянемо ситуацію, коли потрібно змінити макет у Nuxt.js додатку залежно від того, чи перебуває користувач на мобільному пристрої або настільному комп’ютері. Для цього можна скористатися хуком useBreakpoints
з бібліотеки @vueuse/core
, який дозволяє визначити поточний розмір вікна.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<script setup lang="ts"> import { computed } from "vue"; import { useBreakpoints, breakpointsTailwind } from "@vueuse/core"; const breakpoints = useBreakpoints(breakpointsTailwind); const layoutName = computed(() => breakpoints.smaller("md") ? "sidenav-mobile" : "sidenav-desktop", ); </script> <template> <div> {{ breakpoints.smaller("md") }} <!-- це реактивно --> <NuxtLayout :name="layoutName"> <!-- layoutName не є реактивним --> <template #links> <slot name="links"></slot> </template> </NuxtLayout> </div> </template> |
Проблема, з якою стикаються розробники, полягає в тому, що хоча вираз {{ breakpoints.smaller("md") }}
є реактивним і коректно оновлюється при зміні розміру вікна, проперті layoutName
, яке передається в NuxtLayout
як назва макету, не оновлюється реактивно. Це означає, що макет не змінюється динамічно без перезавантаження сторінки.
Основною причиною цієї проблеми є те, що властивості, передані в компоненти як пропси, не можуть бути динамічно змінені в Nuxt.js за замовчуванням після ініціалізації компонента. Для вирішення цієї проблеми існує кілька підходів.
Один з можливих способів – використання глобального об’єкта window
для прослуховування події зміни розміру вікна. При кожній зміні розміру можна примусово оновити компонент, використовуючи ключ компонента, який змінюється при кожній зміні розміру.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<template> <div :key="componentKey"> <NuxtLayout :name="layoutName"> <!-- контент --> </NuxtLayout> </div> </template> <script setup lang="ts"> import { ref, computed } from "vue"; import { useBreakpoints, breakpointsTailwind } from "@vueuse/core"; const breakpoints = useBreakpoints(breakpointsTailwind); const componentKey = ref(0); const layoutName = computed(() => breakpoints.smaller("md") ? "sidenav-mobile" : "sidenav-desktop", ); window.addEventListener('resize', () => { componentKey.value++; }); </script> |
Інший підхід полягає у використанні Vue watcher для спостереження за зміною розміру вікна і оновлення макету відповідно до цього. Цей метод дозволяє зберегти реактивність без необхідності примусового оновлення ключа компонента.
1 2 3 4 5 6 7 8 9 |
<script setup lang="ts"> import { watch } from "vue"; import { useBreakpoints, breakpointsTailwind } from "@vueuse/core"; const breakpoints = useBreakpoints(breakpointsTailwind); const layoutName = ref("sidenav-desktop"); // Початкове значення watch(() => breakpoints.smaller("md"), (isSmall) => { layoutName.value = isSmall ? "sidenav-mobile" : "sidenav-desktop"; }); </script> |
Обидва методи дозволяють динамічно змінювати макет відповідно до розміру екрану без необхідності перезавантаження сторінки. Вибір методу залежить від конкретних потреб проекту та особистих уподобань розробника.
Адаптація макету під різні розміри екранів є важливою частиною розробки сучасних веб-додатків. Nuxt.js пропонує потужні інструменти для роботи з макетами, але для динамічної зміни макету може знадобитися додаткова налаштування. Використання useBreakpoints
з @vueuse/core
та адаптація відповідно до змін розміру екрану дозволяють створити гнучкий і адаптивний дизайн, який забезпечить найкращий досвід користувача на будь-якому пристрої.