詳解Vue渲染列表指令:v-for

2022-08-10 18:01:07

之前的中,我們學習了在Vue中如何通過v-ifv-show根據條件渲染所需要的DOM元素或者模板。在實際的專案中,我們很多時候會碰到將JSON資料中的陣列或物件渲染出列表之類的元素。在Vue中,提供了一個v-for的指令,可以渲染列表。(學習視訊分享:)

v-for 的作用


v-for可以基於源資料多次渲染元素或模板塊。這個指令必須用特定的語法alias in expression,為當前遍歷的元素提供別名:

<div v-for="alias in expression"> {{ alias }}</div>

一般都是給陣列或物件指定別名,除此之外還可以為索引值指定別名,對於物件還可以給value指定別名,常見的幾種情形如下:

<div v-for="item in items">{{ item }}</div>
<div v-for="(item, index) in items">{{ item }} {{ index }}</div>
<div v-for="val in object"></div>
<div v-for="(val, key) in object"></div>
<div v-for="(val, key, index) in object"></div>

其中我們也可以把in換成of作為分隔符,因為它是最接近JavaScript迭代器的語法。

v-for的預設行為試著不改變整體,而是替換元素。迫使其重新排序的元素,你需要提供一個key的特殊屬性:

<div v-for="itme in items" :key="item.id"> {{ item.text }}</div>

接下來,我們看看v-for的一些使用場景。

一個陣列的 v-for


使用v-for指令把陣列的選項列表進行渲染。v-for指令需要使用item in items形式的特殊語法,items是源資料陣列,item是陣列元素迭代的別名。來看一個簡單的範例:

<!-- Template -->
<ul>
    <li v-for="item in items">{{ item }}</li>
</ul>

// JavaScript
var app = new Vue({
    el: '#app',
    data: {
        items: [1, 34, 89, 92, 45, 76, 33]
    }
})

這個時候,陣列items的每個item渲染到對應的li中,在瀏覽器看到的效果如下:

上面的例子是通過v-for把陣列items的每個項迭代出來放到li中,除此之外,還可以把陣列的每個index也遍歷出來。在上面的程式碼的基礎上,咱們修改一下模板:

<ul>
    <li v-for="(item, index) in items">index-{{ index }}: {{ item }}</li>
</ul>

這個時候陣列的索引號也遍歷出來了:

從上面的示列看出來了,你需要哪個元素(HTML的標籤)迴圈,那麼v-for就寫在那個元素上。

上面我們已經可以正常的使用v-for將定義的陣列每一項輸出來。為了加深學習,咱們在上面的範例基礎上增加一項需求,就是對輸出的陣列進行排序。這個時候,咱們需要使用到Vue中的computed屬性。

在Vue中,我們不能汙染源資料,如果我們直接對源資料items通過sort()方法進行排序,將會報錯的:

var app = new Vue({
    el: '#app',
    computed: {
        items: function() {
            return this.items.sort()
        }
    },
    data: {
        items: [1, 34, 89, 92, 45, 76, 33]
    }
})

為了不會汙染Vue中的源資料,需要在computed裡重新宣告一個物件,比如宣告一個sortItems物件:

var app = new Vue({
    el: '#app',
    computed: {
        sortItems: function() {
            return this.items.sort()
        }
    },
    data: {
        items: [1, 34, 89, 92, 45, 76, 3, 12]
    }
})

這個時候,我們的模板也需要做對應的修改:

<ul>
    <li v-for="item in sortItems">{{ item }}</li>
</ul>

如果不出意外的話,你看到的效果將是這樣的:

雖然有變化了,但不是我們想要的排序結果。雖然結果不是我們想要的,但這並不是Vue自身的問題,在JavaScript中也是這樣。如果我們要想真正的實現一個排序效果,那麼需要新增一個JavaScript的陣列的排序函數的功能:

function sortNumber(a, b) {
    return a - b
}

computed裡的程式碼也做一個相應的修改:

computed: {
    sortItems: function() {
        return this.items.sort(sortNumber)
    }
}

這相輸出的效果才真正的是一個正確的排序效果:

上面的例子,我們看到的是是一個簡單的純數位之類的陣列,其其陣列中的每個項也可以是物件,比如:

data: {
    objItems: [
        {
            firstName: 'Jack',
            lastName: 'Li',
            age: 34
        },
        {
            firstName: 'Airen',
            lastName: 'Liao',
            age: 18
        }
    ]
}

我們把模板換成:

 <li v-for="objItem in objItems">{{ objItem.firstName }} {{objItem.lastName}} is {{ objItem.age}} years old!</li>

這個時候看到的效果如下:

在JavaScript中,我們有很多陣列的方法,可以對陣列進行操作,這些方法可以修改一個陣列。其實,在Vue中同樣包含一組觀察陣列變異方法,這些方法將會觸發元素的重新更新(檢視更新),這些方法也是JavaScript中陣列中常看到的方法:push()pop()shift()unshift()splice()sort()reverse()。我們可以在控制檯中簡單的看一下前面的範例中items陣列呼叫變異方法的效果:

Vue不但提供了陣列變異的方法,還提供了替換陣列的方法。變異方法可以通過些方法的呼叫修改源資料中的陣列;除此之外也有對應的非變異方法,比如filter()concat()slice()等。這些方法是不會改變源資料中的原始陣列,但總是返回一個新陣列。當使用這些方法時,可以用新陣列替換舊陣列。

由於JavaScript的限制,Vue不能檢測以下變動的陣列:

  • 當你利用索引直接設定一個項時,例如app.items[indexOfItem] = newValue
  • 當你修改陣列的長度時,例如: app.items.length = newLength

為了解決第一類問題,以下兩種方式都可以實現和app.items[indexOfItem = newValue相同的效果,同時也將觸發狀態更新:

Vue.set(app.items, indexOfItem, newValue)

app.items.splice(indexOfItem, 1, newValue)

為了解決第二類問題,你可以使用splice():

app.items.splice(newLength)

物件的 v-for


v-for除了可以使用在陣列上之外還可以應用在物件上。

<!-- Template -->
<ul>
    <li v-for="value in obj">{{ value }}</li>
</ul>

// JavaScript
obj: {
    firstName: 'Airen',
    lastName: 'Liao',
    age: 30
}

使用v-for可以把obj的每個key對應的value值遍歷出來,並且填到對應的li元素中。效果如下:

你也可以給物件的key遍歷出來:

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

效果如下:

同樣,也可以類似陣列一樣,可以把index索引做為第三個引數:

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

前面提到過,陣列可以變異,但對於物件而言,Vue不能檢測物件屬性的新增或刪除。這主要也是由於JavaScript的限制。不過在Vue中,對於已經建立好的範例,可以使用Vue.set(object, key, value)方法向巢狀物件新增響應式屬性。例如:

var app = new Vue({
    data: {
        obj: {
            name: 'Airen'
        }
    }
})

可以使用類似下面的方式,給obj物件新增一個新的屬性age

Vue.set(app.obj, 'age', 27)

回到我們的範例中給資料來源中的obj新增一個'from'key,而且其對應的value值為'江西'

除了Vue.set()之外,還可以使用app.$set實體方法,它其實就是Vue.set的別名:

mounted(){
    this.$set(this.obj, '職位', '碼農')
}

這裡用到了Vue中的mounted(),和computed一樣,也不知道他在Vue中的作用,同樣放到後面來。我們總是會搞明白的。

有時候你可能需要為已有物件賦予多個新屬性,比如使用Object.assign()_.extend()。在這種情況下,應該用兩個物件的屬性建立一個新的物件。所以,如果你想新增新的響應式屬性,不要像這樣:

Object.assign(this.obj, {
    age: 27,
    favoriteColor: 'Vue Green'
})

應該這樣做:

this.obj = Object.assign({}, this.obj, {
    age: 27,
    favoriteColor: 'Vue Green'
})

一段取值範圍的 v-for


v-for也可以取整數。在這種情況下,它將重複多次模板:

<ul>
    <li v-for="n in 10">{{ n }}</li>
</ul>

結果如下:

v-for 和 一個 <template>


類似於v-if,你也可以利用帶有v-for<template>渲染多個元素,比如:

<ul>
    <template v-for="(value, key) in obj">
        <li>
            <label :for="key">{{ key }}:</label>
            <input type="text" :placeholder="value" :id="key" />
        </li>
    </template>
</ul>

效果如下:

注意了,v-for<template>一起使用的時候,需要把v-for寫在<template>元素上。另外上面的範例中,咱們還使用了Vue的一些其他特性,但這些特性不是這節內容所要學習的。後面我們會有機會一一介紹的。

一個元件的 v-for


在自定義元件裡,也可以像任何普通元素一樣用v-for

<my-component v-for="item in items" :key="item.id"></my-component>

2.2.0+ 的版本里,當在元件中使用 v-for 時,key 現在是必須的。

然而他不能自動傳遞資料到元件裡,因為元件有自己獨立的作用域。為了傳遞迭代資料到元件裡,我們要用 props

<my-component
    v-for="(item, index) in items"
    v-bind:item="item"
    v-bind:index="index"
    v-bind:key="item.id"
></my-component>

不自動注入 item 到元件裡的原因是,因為這使得元件會與 v-for 的運作緊密耦合。在一些情況下,明確資料的來源可以使元件可重用。

來看一個簡單的Todo範例:

<div id="todo">
    <input
        v-model="newTodoText"
        v-on:keyup.enter="addNewTodo"
        placeholder="Add a todo"
    />

    <ul>
        <li
            is="todoItem"
            v-for="(todo, index) in todos"
            v-bind:title="todo"
            v-on:remove="todos.splice(index, 1)"></li>
    </ul>
</div>

Vue.component('todoItem', {
    template:`
        <li>
            {{ title }}
            <button v-on:click="$emit('remove')">x</button>
        </li>
    `,
    props: ['title']
})

new Vue({
    el: '#todo',
    data: {
        newTodoText: '',
        todos: [
            'Do the dishes',
            'Take out the trash',
            'Mow the lawn'
        ]
    },
    methods: {
        addNewTodo: function() {
            this.todos.push(this.newTodoText)
            this.newTodoText = ''
        }
    }
})

1.gif

總結


這篇文章主要總結了Vue的v-for指令。通過這個指令,配合資料來源中的陣列或者物件,我們可以很方便的生成列表。這也常常稱為列表渲染。當然配合一些模板,我們可以做出一些特有的功能和效果。比如文章中最後一個Todo 列表,使用v-for很易實現。

(學習視訊分享:、)

以上就是詳解Vue渲染列表指令:v-for的詳細內容,更多請關注TW511.COM其它相關文章!