Skip to content

Vykreslování seznamu

v-for

Pro vykreslení senzamu založeného na hodnotách pole můžeme použít direktivu v-for. Zápis v-for vyžaduje speciální syntaxi ve formě item in items, kde items je zdrojové datové pole a item je alias pro prvek pole, přes které se iteruje:

js
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
js
data() {
  return {
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
template
<li v-for="item in items">
  {{ item.message }}
</li>

Uvnitř elementu s v-for mají výrazy šablony přístup ke všem vlastnostem nadřazeného scope. Navíc v-for podporuje ještě volitelný druhý alias pro index aktuální položky:

js
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
js
data() {
  return {
    parentMessage: 'Parent',
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
template
<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
  • Parent - 0 - Foo
  • Parent - 1 - Bar
  • Scope proměnné z v-for je obdobný jako v následujícímu JavaScript kódu:

    js
    const parentMessage = 'Parent'
    const items = [
      /* ... */
    ]
    
    items.forEach((item, index) => {
      // má přístup do vnejšího scope`parentMessage`
      // ale `item` a `index` jsou dostupné pouze zde
      console.log(parentMessage, item.message, index)
    })

    Všimněte si, že se hodnota v-for shoduje s definicí callback funkce forEach. Dokonce můžete použít destrukturování na alias položky v-for podobně jako na parametry funkce:

    template
    <li v-for="{ message } in items">
      {{ message }}
    </li>
    
    <!-- with index alias -->
    <li v-for="({ message }, index) in items">
      {{ message }} {{ index }}
    </li>

    Pro vnořené v-for funguje scope také stejně jako ve vnořených funkcích. Každý scope v-for má přístup do rodičovského scope:

    template
    <li v-for="item in items">
      <span v-for="childItem in item.children">
        {{ item.message }} {{ childItem }}
      </span>
    </li>

    Aby byl zápis bližší JavaScript syntaxi pro iterátory, můžete také místo in použít of:

    template
    <div v-for="item of items"></div>

    v-for nad objektem

    Direktivu v-for můžete také použít pro iteraci nad vlastnostmi objektu. Pořadí iterace bude záviset na výsledku volání funkce Object.values() na daný objekt:

    js
    const myObject = reactive({
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    })
    js
    data() {
      return {
        myObject: {
          title: 'How to do lists in Vue',
          author: 'Jane Doe',
          publishedAt: '2016-04-10'
        }
      }
    }
    template
    <ul>
      <li v-for="value in myObject">
        {{ value }}
      </li>
    </ul>

    Můžete také úvést druhý alias (klíč) pro název vlastnosti:

    template
    <li v-for="(value, key) in myObject">
      {{ key }}: {{ value }}
    </li>

    A ještě další pro její pořadí:

    template
    <li v-for="(value, key, index) in myObject">
      {{ index }}. {{ key }}: {{ value }}
    </li>

    v-for nad rozsahem hodnot

    v-for akceptuje jako parametr i číslo. V tomto případě se bude šablona opakovat n-krát, na základě rozsahu 1...n.

    template
    <span v-for="n in 10">{{ n }}</span>

    Dejte pozor, že n začíná s úvodníh hodnotou 1 místo obvyklé 0.

    v-for nad <template>

    Podobně jako u v-if, je možné tag <template> použití i s v-for pro vícenásobné vykreslení bloku. Například:

    template
    <ul>
      <template v-for="item in items">
        <li>{{ item.msg }}</li>
        <li class="divider" role="presentation"></li>
      </template>
    </ul>

    v-for s v-if

    Poznámka

    Nedoporučuje se používat v-if a v-for na stejném prvku kvůli jejich implicitní prioritě. Podrobnosti naleznete v Průvodci stylováním.

    Když existují na stejném elementu, v-if má vyšší prioritu než v-for. To znamená, že podmínka v-if nebude mít přístup k proměnným z v-for scope:

    template
    <!--
    Toto vyvolá výjimku, protože "toto"
    není definovaná jako proměnná instance
    -->
    <li v-for="todo in todos" v-if="!todo.isComplete">
      {{ todo.name }}
    </li>

    Toto lze napravit přesunutím v-for do obalujícího <template> tagu (což je také přehlednější):

    template
    <template v-for="todo in todos">
      <li v-if="!todo.isComplete">
        {{ todo.name }}
      </li>
    </template>

    Udržování stavu pomocí key

    Když Vue aktualizuje seznam prvků vykreslených pomocí v-for, ve výchozím nastavení používá strategii „opravy na místě“. Pokud se pořadí datových položek změnilo, namísto přesování prvků DOM tak, aby odpovídaly pořadí položek, Vue každý prvek opraví na jeho místě a zajistí, aby odrážel to, co by se na daném místě mělo vykreslit.

    Tento výchozí režim je efektivní, ale vhodný pouze tehdy, když výsledek vykreslení vašeho seznamu nezávisí na stavu podřízené komponenty nebo dočasném stavu DOM (např. vstupní hodnoty formulářů).

    Chcete-li Vue poskytnout nápovědu, aby mohlo sledovat identitu každého uzlu, a tedy znovupoužít a změnit pořadí existujících prvků, musíte pro každou položku poskytnout jedinečný atribut key:

    template
    <div v-for="item in items" :key="item.id">
      <!-- content -->
    </div>

    Při použití <template v-for>, by měl být key umístěn do <template> tagu:

    template
    <template v-for="todo in todos" :key="todo.name">
      <li>{{ todo.name }}</li>
    </template>

    Poznámka

    Zde uvedený key je speciální atribut propojený s v-bind. Nemělo by se zaměňovat s klíčem pro vlastnosti při použití v-for nad objektem.

    Je doporučeno použití atributu key s v-for, kdykoli je to možné. Výjimkou mohou být situace, kdy je iterovaný obsah DOM velmi jednoduchý (tj. neobsahuje žádné komponenty nebo stavové elementy DOM), nebo se záměrně spoléháte na výchozí chování pro zvýšení výkonu.

    Direktiva key očekává vazbu na primitivní hodnoty – tedy string a number. Nepoužívejte jako klíče v-for objekty. Podrobné použití atributu key naleznete v API dokumentaci pro key.

    v-for nad komponentou

    Tato sekce předpokládá znalost základů komponent. Klidně ji teď přeskočte a vraťte se později.

    Je možné použít v-for přímo na komponentu, jako by to byl jiný standardní element (nezapomeňte definovat key):

    template
    <MyComponent v-for="item in items" :key="item.id" />

    To však komponentě automaticky nepředá žádná data, protože komponenty mají své vlastní izolované scope. Abychom předali do komponenty iterovaná data, měli bychom použít také vlastnosti (props):

    template
    <MyComponent
      v-for="(item, index) in items"
      :item="item"
      :index="index"
      :key="item.id"
    />

    Důvodem, proč se item do komponenty automaticky nevkládá, je, že díky tomu by byla komponenta pevně spojena s tím, jak funguje v-for. Určovat explicitně odkud data pocházejí umožňuje, že je komponenta znovupoužitelná i v jiných situacích.

    Podívejte se na tento příklad jednoduchého TODO listu, abyste viděli, jak vykreslit list komponent pomocí v-for s předáním různých dat do každé instance.

    Podívejte se na tento příklad jednoduchého TODO listu, abyste viděli, jak vykreslit list komponent pomocí v-for s předáním různých dat do každé instance.

    Detekce změny pole

    Změnové funkce

    Vue umí detekovat, když jsou volány změnové funkce reaktivního pole, a vyvolat potřebné aktualizace. Tyto změnové funkce jsou:

    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()

    Nahrazení pole

    Změnové funkce, jak název napovídá, mění původní pole, na kterém jsou volány. Pro srovnání existují i funkce, které pole nemění, např. filter(), concat() a slice(), které nemění původní pole, ale vždy vrátí nové pole. Při práci s těmito funkcemi bychom měli staré pole nahradit novým:

    js
    // `items` je ref obsahující pole
    items.value = items.value.filter((item) => item.message.match(/Foo/))
    js
    this.items = this.items.filter((item) => item.message.match(/Foo/))

    Možná byste si mysleli, že to způsobí, že Vue zahodí stávající DOM a vykreslí celý seznam znovu – naštěstí tomu tak není. Vue implementuje některé chytré heuristiky pro maximalizaci znovupoužití DOM elementů, takže nahrazení jednoho pole jiným polem obsahujícím překrývající se objekty je velmi efektivní operace.

    Zobrazení filtrovaných/seřazených výsledků

    Někdy chceme zobrazit filtrovanou nebo seřazenou verzi pole, aniž bychom skutečně měnili nebo resetovali původní data. V tomto případě můžete vytvořit computed proměnnou, která vrátí pole filtrované nebo seřazené.

    Například:

    js
    const numbers = ref([1, 2, 3, 4, 5])
    
    const evenNumbers = computed(() => {
      return numbers.value.filter((n) => n % 2 === 0)
    })
    js
    data() {
      return {
        numbers: [1, 2, 3, 4, 5]
      }
    },
    computed: {
      evenNumbers() {
        return this.numbers.filter(n => n % 2 === 0)
      }
    }
    template
    <li v-for="n in evenNumbers">{{ n }}</li>

    V situacích, kdy computed proměnné nejsou proveditelné (např. uvnitř vnořených v-for cyklů), můžete použít funkci:

    js
    const sets = ref([
      [1, 2, 3, 4, 5],
      [6, 7, 8, 9, 10]
    ])
    
    function even(numbers) {
      return numbers.filter((number) => number % 2 === 0)
    }
    js
    data() {
      return {
        sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
      }
    },
    methods: {
      even(numbers) {
        return numbers.filter(number => number % 2 === 0)
      }
    }
    template
    <ul v-for="numbers in sets">
      <li v-for="n in even(numbers)">{{ n }}</li>
    </ul>

    U computed proměnných buďte opatrní s reverse() a sort()! Tyto dvě funkce mění původní pole, čemuž je u computed getterů třeba se vyhnout. Před voláním těchto funkcí vytvořte kopii původního pole:

    diff
    - return numbers.reverse()
    + return [...numbers].reverse()
    Vykreslování seznamu has loaded