Skip to content

Renderowanie Listy

v-for

Możemy użyć dyrektywy v-for do renderowania listy elementów na podstawie tablicy. Dyrektywa v-for wymaga specjalnej składni w postaci item in items, gdzie items jest tablicą danych źródłowych, a item jest aliasem dla elementu tablicy, po którym następuje iteracja:

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>

Wewnątrz zakresu v-for, wyrażenia szablonów mają dostęp do wszystkich właściwości zakresu nadrzędnego. Dodatkowo, v-for obsługuje także opcjonalny drugi alias dla indeksu bieżącego elementu:

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
  • Zakres zmiennych w v-for jest podobny do tego w następującym przykładzie JavaScript:

    js
    const parentMessage = 'Parent'
    const items = [
      /* ... */
    ]
    
    items.forEach((item, index) => {
      // ma dostęp do zewnętrznego zakresu `parentMessage`.
      // ale `item` i `index` są dostępne tylko w tym miejscu
      console.log(parentMessage, item.message, index)
    })
    

    Zauważ, że wartość v-for pasuje do nazwy funkcji wywołania zwrotnego forEach. W rzeczywistości możesz użyć destrukcji na aliasie elementu v-for podobnie jak w przypadku destrukturyzacji argumentów funkcji:

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

    Dla zagnieżdżonych v-for, skalowanie również działa podobnie jak dla zagnieżdżonych funkcji. Każdy zakres v-for ma dostęp do zakresów nadrzędnych:

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

    Możesz także użyć of jako separatora zamiast in, tak aby było to bliższe składni JavaScript dla iteracji:

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

    v-for z Obiektem

    Możesz także użyć v-for do iteracji po właściwościach obiektu. Kolejność iteracji będzie oparta na wyniku wykonania Object.keys() na obiekcie:

    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>
    

    Można również podać drugi alias dla nazwy właściwości (np. klucz):

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

    I jeszcze jeden do indeksu:

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

    v-for z Zakresem

    v-for może również przyjmować liczbę całkowitą. W tym przypadku powtórzy on szablon tyle razy, na podstawie zakresu 1...n.

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

    Zwróć uwagę, że n zaczyna się od wartości początkowej 1 zamiast 0.

    v-for na <template>

    Podobnie jak w przypadku szablonu v-if, możesz także użyć znacznika <template> z v-for do renderowania bloku wielu elementów. Na przykład:

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

    v-for z v-if

    Note

    Nie zaleca się używania v-if i v-for na tym samym elemencie z powodu ukrytego pierwszeństwa. Po szczegóły odsyłam do style-guide.

    Gdy istnieją na tym samym drzewie, v-if ma wyższy priorytet niż v-for. Oznacza to, że warunek v-if nie będzie miał dostępu do zmiennych z zakresu v-for:

    template
    <!--
    Spowoduje to wyświetlenie błędu, ponieważ właściwość "todo"
    nie jest zdefiniowana w instancji.
    -->
    <li v-for="todo in todos" v-if="!todo.isComplete">
      {{ todo.name }}
    </li>
    

    Można to naprawić, przenosząc v-for do opakowującego znacznika <template> (który jest też bardziej jednoznaczny):

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

    Utrzymywanie stanu za pomocą key

    Gdy Vue aktualizuje listę elementów wyrenderowanych za pomocą v-for, domyślnie używa strategii " łatania w miejscu". Jeśli kolejność elementów danych uległa zmianie, zamiast przesuwać elementy DOM, aby dopasować je do kolejności elementów, Vue poprawi każdy element w miejscu i upewni się, że odzwierciedla on to, co powinno być renderowane w danym indeksie.

    Ten domyślny tryb jest wydajny, ale jest odpowiedni tylko wtedy, gdy wynik renderowania listy nie zależy od stanu komponentów potomnych lub tymczasowego stanu DOM (np. wartości wejściowych formularza).

    Aby dać Vue wskazówkę, dzięki której będzie ono mogło śledzić tożsamość każdego elementu, a tym samym ponownie wykorzystywać i zmieniać kolejność istniejących elementów, należy podać unikalny atrybut key dla każdego elementu:

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

    Podczas używania <template v-for>, klucz powinien być umieszczony na szablonie <template>:

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

    Note

    key jest tu specjalnym atrybutem wiązanym za pomocą v-bind. Nie należy go mylić ze zmienną kluczową właściwości, gdy [używamy v-for z obiektem] (#v-for-with-an-object).

    Zaleca się, aby atrybut v-for był wyposażony w atrybut key zawsze, gdy jest to możliwe, chyba że iterowana zawartość DOM jest prosta (tzn. nie zawiera żadnych komponentów lub elementów DOM), lub celowo polegasz na domyślnym zachowaniu by zwiększyć wydajność.

    Wiązanie key oczekuje wartości prymitywnych - tj. strings i numbers. Nie należy używać obiektów jako kluczy v-for. Dla szczegółowego użycia atrybutu key, zobacz dokumentację key API.

    v-for z Componentem

    Ta sekcja zakłada znajomość Komponentów. Nie krępuj się pominąć jej i wrócić do niej później.

    Możesz bezpośrednio użyć v-for na komponencie, jak na każdym normalnym elemencie (nie zapomnij podać key):

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

    Nie spowoduje to jednak automatycznego przekazania żadnych danych do komponentu, ponieważ komponenty mają własne, izolowane zakresy. Aby przekazać iterowane dane do komponentu, należy również użyć props:

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

    Powodem, dla którego nie wstrzykujemy automatycznie item do komponentu jest to, że czyni to komponent ściśle powiązanym z tym, jak działa v-for. Wyraźne określenie, skąd pochodzą dane, czyni komponent przydatnym w innych sytuacjach.

    Sprawdź ten przykład prostej listy rzeczy do zrobienia to see how to render a list of components using v-for, passing different data to each instance.

    Sprawdź ten przykład prostej listy rzeczy do zrobienia to see how to render a list of components using v-for, passing different data to each instance.

    Wykrywanie zmian w tablicy

    Metody mutacji

    Vue opakowuje metody moderacji obserwowanej tablicy tak, że będą one również wywoływać aktualizacje widoku. Te metody to:

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

    Zamiana tablicy

    Metody modyfikujące, jak sama nazwa wskazuje, modyfikują oryginalną tablicę, na której zostały wywołane. Dla porównania, istnieją również metody niemodyfikujące, np. filter(), concat() i slice(), które nie mutują oryginalnej tablicy, ale zawsze zwracają nową tablicę. Podczas pracy z metodami niemutującymi należy zastąpić starą tablicę nową:

    js
    // `item` jest referencją z wartością tablicową
    items.value = items.value.filter((item) => item.message.match(/Foo/))
    
    js
    this.items = this.items.filter((item) => item.message.match(/Foo/))
    

    Można by pomyśleć, że spowoduje to, iż Vue wyrzuci istniejący DOM i ponownie wyrenderuje całą listę - na szczęście tak nie jest. Vue implementuje pewne inteligentne mechanizmy pozwalające na maksymalne ponowne wykorzystanie elementów DOM, więc zastąpienie tablicy inną tablicą zawierającą nakładające się obiekty jest bardzo wydajną operacją.

    Wyświetlanie przefiltrowanych/sortowanych wyników

    Czasami chcemy wyświetlić przefiltrowaną lub posortowaną wersję tablicy bez faktycznego mutowania lub resetowania oryginalnych danych. W takim przypadku można utworzyć computed property, która zwraca przefiltrowaną lub posortowaną tablicę.

    Na przykład:

    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>
    

    W sytuacjach, gdy zastosowanie computed properties nie jest możliwe (np. wewnątrz zagnieżdżonych pętli v-for), można użyć metody:

    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>
    

    Bądź ostrożny z reverse() i sort() w computed property! Te dwie metody zmutują oryginalną tablicę, co powinno być unikane w computed getterach. Przed wywołaniem tych metod należy utworzyć kopię oryginalnej tablicy:

    diff
    - return numbers.reverse()
    + return [...numbers].reverse()
    
    Renderowanie Listy has loaded