Pravidla priority A: Zásadní (prevence chyb)
Tato pravidla pomáhají předcházet chybám, proto se je za každou cenu naučte a dodržujte je. Výjimky mohou existovat, ale měly by být velmi vzácné a měly by být dělány pouze osobami s odbornými znalostmi jak JavaScriptu, tak Vue.
Používejte víceslovné názvy komponent
Názvy vašich vlastních komponent by měly být vždy víceslovné, s výjimkou kořenových komponent App
. To předchází konfliktům se stávajícími a potenciálními budoucími HTML elementy, protože všechny HTML elementy jsou jednoslovné.
Špatně
template
<!-- pre-kompilovaná šablona -->
<Item />
<!-- DOM šablona -->
<item></item>
Dobře
template
<!-- pre-kompilovaná šablona -->
<TodoItem />
<!-- DOM šablona -->
<todo-item></todo-item>
Používejte detailní definice vlastností
V hotovém kódu by definice vlastností (props) měly být vždy co nejpodrobnější, přinejmenším by měly specifikovat typ(y).
Podrobné vysvětlení
Podrobná definice vlastností má dvě výhody:
- Dokumentují API komponenty, takže je snadněji vidět, jak má být komponenta používána.
- Během vývoje vás Vue upozorní, pokud budou komponentě předávané vlastnosti v chybném formátu, což vám pomůže zachytit potenciální zdroje chyb.
Špatně
js
// toto je OK pouze během prototypování
const props = defineProps(['status'])
Dobře
js
const props = defineProps({
status: String
})
js
// ještě lepší
const props = defineProps({
status: {
type: String,
required: true,
validator: (value) => {
return ['syncing', 'synced', 'version-conflict', 'error'].includes(
value
)
}
}
})
Používejte v-for
spolu s klíčem
key
společně s v-for
je v komponentách vždy vyžadován, za účelem udržení interního stavu komponent v podstromu. Ovšem i u elementů je dobrým zvykem udržovat předvídatelné chování, jako je stálost objektu při animacích.
Podrobné vysvětlení
Řekněme že máte seznam TODO prvků:
js
const todos = ref([
{
id: 1,
text: 'Naucit se pouzivat v-for'
},
{
id: 2,
text: 'Naucit se pouzivat key'
}
])
Pak je seřadíte podle abecedy. Při aktualizaci DOM Vue optimalizuje vykreslování tak, aby se provedly co nejmenší změny DOM. To může znamenat odstranění prvního TODO prvku a jeho opětovné přidání na konec seznamu.
Problém je, že existují případy, kdy je důležité nesmazat prvky, které zůstanou v DOM. Například můžete chtít použít <transition-group>
k animaci řazení seznamu nebo zachovat focus, pokud je vykreslený prvek <input>
. V těchto případech přidání jedinečného klíče pro každou položku (např. :key="todo.id"
) řekne Vue, jak se chovat předvídatelněji.
Podle našich zkušeností je lepší vždy přidat jedinečný klíč, abyste se vy a váš tým jednoduše nikdy nemuseli starat o tyto okrajové případy. Pak ve vzácných, výkonově kritických scénářích, kde není stálost objektu nutná, můžete udělat vědomou výjimku.
Špatně
template
<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
Dobře
template
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
Vyvarujte se v-if
dohromady s v-for
Nikdy nepoužívejte v-if
ma stejný element jako v-for
.
Existují dva běžné případy, kdy to může být lákavé:
Při filtrování položek v seznamu (např.
v-for="user in users" v-if="user.isActive"
). V těchto případech nahraďteusers
novou computed proměnnou, která vrátí filtrovaný seznam (např.activeUsers
).Aby se zabránilo vykreslování seznamu, který by měl být skrytý (např.
v-for="user in users" v-if="shouldShowUsers"
). V těchto případech přesuňtev-if
na mateřeský element (např.ul
,ol
).
Podrobné vysvětlení
Když Vue zpracovává direktivy, v-if
má vyšší priorotu než v-for
. V této šabloně tedy:
template
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
vyvolá výjimku, protože v-if
direktiva bude vyhodnocena první a proměnná user
, přes kterou se iteruje nebude v tom okamžiku existovat.
To se dá napravit iterací přes computed proměnnou, například takto:
js
const activeUsers = computed(() => {
return users.filter((user) => user.isActive)
})
template
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
Nebo můžete použít tag <template>
s v-for
, kterým obalíte <li>
element:
template
<ul>
<template v-for="user in users" :key="user.id">
<li v-if="user.isActive">
{{ user.name }}
</li>
</template>
</ul>
Špatně
template
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
Dobře
template
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
template
<ul>
<template v-for="user in users" :key="user.id">
<li v-if="user.isActive">
{{ user.name }}
</li>
</template>
</ul>
Používejte omezené stylování komponent
V aplikacích mohou být styly na nejvyšší úrovni komponenty App
a v komponentách pro layout globální, ale všechy ostatní komponenty by měly mít styly vždy omezené (scoped).
To platí pouze pro Single-File komponenty (SFC). Není nezbytné používat atribut scoped
. Omezení lze zajistit pomocí CSS modulů, a class-based strategie jako je BEM, či jiné knihovny/konvence.
Komponenty knihoven by nicméně měly class-based strategii místo používání atributu scoped
upřednostňovat.
Díky tomu je přepisování interních stylů snazší, s lidsky-čitelnými názvy tříd, které nejsou příliš specifické, ale přesto je velmi nepravděpodobné, že by vedly ke konfliktu.
Podrobné vysvětlení
Pokud vyvíjíte velký projekt, spolupracujete s dalšími vývojáři nebo někdy využijete HTML/CSS třetí strany (např. od Auth0), konzistentní omezení zajistí, že se vaše styly budou vztahovat pouze na komponenty, pro které jsou určeny.
Kromě atributu scoped
může použití jedinečných názvů tříd pomoci zajistit, že se CSS třetí strany nebude aplikovat na vaše vlastní HTML. Mnoho projektů například používá názvy tříd button
, btn
nebo icon
, takže i když nepoužíváte strategii jako je BEM, přidání předpony specifické pro aplikaci a/nebo komponentu (např. ButtonClose-icon
) může poskytnout určitou ochranu před nežádoucími efekty.
Špatně
template
<template>
<button class="btn btn-close">×</button>
</template>
<style>
.btn-close {
background-color: red;
}
</style>
Dobře
template
<template>
<button class="button button-close">×</button>
</template>
<!-- Použití atributu `scoped` -->
<style scoped>
.button {
border: none;
border-radius: 2px;
}
.button-close {
background-color: red;
}
</style>
template
<template>
<button :class="[$style.button, $style.buttonClose]">×</button>
</template>
<!-- Použití CSS modulů -->
<style module>
.button {
border: none;
border-radius: 2px;
}
.buttonClose {
background-color: red;
}
</style>
template
<template>
<button class="c-Button c-Button--close">×</button>
</template>
<!-- Použití BEM konvence -->
<style>
.c-Button {
border: none;
border-radius: 2px;
}
.c-Button--close {
background-color: red;
}
</style>