Skip to content

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í
props: ['status']

Dobře

js
props: {
  status: String
}
js
// ještě lepší
props: {
  status: {
    type: String,
    required: true,

    validator: value => {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].includes(value)
    }
  }
}

Š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
data() {
  return {
    todos: [
      {
        id: 1,
        text: 'Naučit se používat v-for'
      },
      {
        id: 2,
        text: 'Naučit se používat key'
      }
    ]
  }
}
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ďte users 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ňte v-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
computed: {
  activeUsers() {
    return this.users.filter(user => user.isActive)
  }
}
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>
Pravidla priority A: Zásadní (prevence chyb) has loaded