Pierwszy rzut oka jak wyglądają „prawdziwe komponenty” z composition API w normalnym projekcie Laravelowym lub jakimkolwiek innym większym. Do dzieła.
Poprzednio napisaliśmy taki komponent:
app.component('person-component', {
props: ['name'],
template: `<li>Name: {{name}}</li>`
});
Używaliśmy go w ten sposób:
<div id="app">
<ul>
<person-component
name="John Static"></person-component>
<person-component
v-for="person in people"
:key="person.id"
:name="person.name"></person-component>
</ul>
</div>
Natomiast powiedzieliśmy sobie, że w prawdziwym świecie nie tworzymy ani apek Vue przez createApp, ani komponentów w ten sposób. Najwyższa pora zobaczyć jak wygląda jakiś komponent (np. utworzony przez Laravel Breeze z opcją Vue) w realnym projekcie.
Proszę:
<script setup>
defineProps({
message: {
type: String,
},
});
</script>
<template>
<div v-show="message">
<p class="text-sm text-red-600">
{{ message }}
</p>
</div>
</template>
Mamy tutaj composition API (które weszło z Vue 3, nie jest jakimś wynalazkiem Laravela i Inetrii), czyli modularność i podział na trzy segmenty:
- script setup, czyli JS
- template, czyli markup
- style (z atrybutem scoped lub bez, chyba samo się tłumaczy) czyli style
No to jest Laravel, który bardzo lubi Tailwinda, więc tutaj akurat mamy klasy Tailwinda, żadnego tagu style. Plik ma rozszerzenie vue.
I Vue ogarnia, że jak jest script setup, to JS, jak template to markup, jak style, to style CSS. Pamiętać musimy:
- script z atrybutem setup
- wiele rzeczy zazwyczaj dostępnych wcześniej teraz musimy importować
- template musi mieć jeden root/top-level element
- style może mieć atrybut scoped, aby miało zasięg tylko do komponentu
Jak wyglądają te importy? Ano tak:
<script setup>
import { computed, onMounted, onUnmounted, watch } from 'vue';
const props = defineProps({
show: {
type: Boolean,
default: false,
},
maxWidth: {
type: String,
default: '2xl',
},
closeable: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['close']);
watch(
() => props.show,
() => {
if (props.show) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = null;
}
}
);
const close = () => {
if (props.closeable) {
emit('close');
}
};
const closeOnEscape = (e) => {
if (e.key === 'Escape' && props.show) {
close();
}
};
onMounted(() => document.addEventListener('keydown', closeOnEscape));
onUnmounted(() => {
document.removeEventListener('keydown', closeOnEscape);
document.body.style.overflow = null;
});
//(...)
</script>
Wygląda trochę strasznie, ale to dlatego, że po pierwsze niektórych tematów nie przerobiliśmy (emit, computed styles), a po drugie nie jesteśmy przyzwyczajeni do composition API.
Natomiast jeżeli popatrzymy na dokumentację Vue, to tam jest tylko composition API.
Teraz w ramach ćwiczenia możemy sobie poczytać dokumentację Vue i porównać z naszymi kodami. Zobaczmy, że tam jest w zasadzie tylko composition API oraz przykłady z tak napisanymi komponentami.
To, co robiliśmy dotychczas (createApp i inne zabawy) jest przestarzałe i musieliśmy jakoś bezboleśnie te tematy wprowadzić. Na razie jesteśmy na etapie, w którym nauczyliśmy się czytać dokumentację Vue oraz ogarniamy czym jest framework frontendowy, jego koncepty (re-rendery, inne takie).
Prawdziwa nauka Vue, w kontekście komponentów + integracji z Laravelem dopiero się zaczyna. Jak komuś podoba się to, co robiliśmy do tej pory, ale nie chce się w komponenty bawić, powinien wybrać Alpine (Breeze daje możliwość używania Alpine + Blade Components, też fajna opcja).