列表渲染

用 v-for 把一個(gè)數(shù)組對(duì)應(yīng)為一組元素

我們用 v-for 指令根據(jù)一組數(shù)組的選項(xiàng)列表進(jìn)行渲染艇纺。v-for 指令需要使用 item in items 形式的特殊語(yǔ)法硅确,items 是源數(shù)據(jù)數(shù)組并且 item 是數(shù)組元素迭代的別名。

                                                                                         HTML
<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
                                                                                         JS
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

在 v-for 塊中工秩,我們擁有對(duì)父作用域?qū)傩缘耐耆L問(wèn)權(quán)限涵妥。v-for 還支持一個(gè)可選的第二個(gè)參數(shù)為當(dāng)前項(xiàng)的索引。

                                                                                        HTML
<ul id="example-2">
 <li v-for="(item, index) in items">
   {{ parentMessage }} - {{ index }} - {{ item.message }}
 </li>
</ul>
                                                                                         JS
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

你也可以用 of 替代 in 作為分隔符乖寒,因?yàn)樗亲罱咏?JavaScript 迭代器的語(yǔ)法:

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

一個(gè)對(duì)象的v-for

你也可以用 v-for 通過(guò)一個(gè)對(duì)象的屬性來(lái)迭代猴蹂。

                                                                                        HTML
<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
                                                                                        JS
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
  }
})
你也可以提供第二個(gè)的參數(shù)為鍵名:
                                                                                        HTML
<div v-for="(value, key) in object">
  {{ key }}: {{ value }}
</div>
第三個(gè)參數(shù)為索引:
                                                                                        HTML
<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }}: {{ value }}
</div>

注意: 在遍歷對(duì)象時(shí),是按 Object.keys() 的結(jié)果遍歷楣嘁,但是不能保證它的結(jié)果在不同的 JavaScript 引擎下是一致的晕讲。

key

當(dāng) Vue.js 用 v-for 正在更新已渲染過(guò)的元素列表時(shí),它默認(rèn)用“就地復(fù)用”策略马澈。如果數(shù)據(jù)項(xiàng)的順序被改變瓢省,Vue 將不會(huì)移動(dòng) DOM 元素來(lái)匹配數(shù)據(jù)項(xiàng)的順序, 而是簡(jiǎn)單復(fù)用此處每個(gè)元素痊班,并且確保它在特定索引下顯示已被渲染過(guò)的每個(gè)元素勤婚。

這個(gè)默認(rèn)的模式是高效的,但是只適用于不依賴子組件狀態(tài)或臨時(shí) DOM 狀態(tài) (例如:表單輸入值) 的列表渲染輸出涤伐。

為了給 Vue 一個(gè)提示馒胆,以便它能跟蹤每個(gè)節(jié)點(diǎn)的身份缨称,從而重用和重新排序現(xiàn)有元素,你需要為每項(xiàng)提供一個(gè)唯一 key 屬性祝迂。理想的 key 值是每項(xiàng)都有的唯一 id睦尽。這個(gè)特殊的屬性相當(dāng)于 Vue 1.x 的 track-by ,但它的工作方式類似于一個(gè)屬性型雳,所以你需要用 v-bind 來(lái)綁定動(dòng)態(tài)值 (在這里使用簡(jiǎn)寫(xiě)):

                                                                                        HTML
<div v-for="item in items" :key="item.id">
  <!-- 內(nèi)容 -->
</div>

建議盡可能在使用 v-for 時(shí)提供 key当凡,除非遍歷輸出的 DOM 內(nèi)容非常簡(jiǎn)單,或者是刻意依賴默認(rèn)行為以獲取性能上的提升纠俭。

因?yàn)樗?Vue 識(shí)別節(jié)點(diǎn)的一個(gè)通用機(jī)制沿量,key 并不與 v-for 特別關(guān)聯(lián),key 還具有其他用途冤荆,我們將在后面的指南中看到其他用途朴则。

數(shù)據(jù)更新檢測(cè)

變異方法

Vue 包含一組觀察數(shù)組的變異方法,所以它們也將會(huì)觸發(fā)視圖更新钓简。這些方法如下:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()
    你打開(kāi)控制臺(tái)乌妒,然后用前面例子的 items 數(shù)組調(diào)用變異方法:
    example1.items.push({ message: 'Baz' }) 。

替換數(shù)組

變異方法 (mutation method)外邓,顧名思義撤蚊,會(huì)改變被這些方法調(diào)用的原始數(shù)組。相比之下坐榆,也有非變異 (non-mutating method) 方法,例如:filter(), concat() 和 slice() 冗茸。這些不會(huì)改變?cè)紨?shù)組席镀,但總是返回一個(gè)新數(shù)組。當(dāng)使用非變異方法時(shí)夏漱,可以用新數(shù)組替換舊數(shù)組:

                                                                                        JS
example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

你可能認(rèn)為這將導(dǎo)致 Vue 丟棄現(xiàn)有 DOM 并重新渲染整個(gè)列表豪诲。幸運(yùn)的是,事實(shí)并非如此挂绰。Vue 為了使得 DOM 元素得到最大范圍的重用而實(shí)現(xiàn)了一些智能的屎篱、啟發(fā)式的方法,所以用一個(gè)含有相同元素的數(shù)組去替換原來(lái)的數(shù)組是非常高效的操作葵蒂。

注意事項(xiàng)

由于 JavaScript 的限制交播,Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:
1.當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如:vm.items[indexOfItem] = newValue
2.當(dāng)你修改數(shù)組的長(zhǎng)度時(shí)践付,例如:vm.items.length = newLength

舉個(gè)例子:

                                                                                        JS
var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是響應(yīng)性的
vm.items.length = 2 // 不是響應(yīng)性的

為了解決第一類問(wèn)題秦士,以下兩種方式都可以實(shí)現(xiàn)和 vm.items[indexOfItem] = newValue 相同的效果,同時(shí)也將觸發(fā)狀態(tài)更新:

                                                                                        JS
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
                                                                                        JS
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

你也可以使用 vm.$set 實(shí)例方法永高,該方法是全局方法 Vue.set 的一個(gè)別名:

                                                                                        JS
vm.$set(vm.items, indexOfItem, newValue)

為了解決第二類問(wèn)題隧土,你可以使用 splice:

                                                                                        JS
vm.items.splice(newLength)

對(duì)象更改檢測(cè)注意事項(xiàng)

還是由于 JavaScript 的限制提针,Vue 不能檢測(cè)對(duì)象屬性的添加或刪除:

                                                                                        JS
var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 現(xiàn)在是響應(yīng)式的

vm.b = 2
// `vm.b` 不是響應(yīng)式的

對(duì)于已經(jīng)創(chuàng)建的實(shí)例,Vue 不能動(dòng)態(tài)添加根級(jí)別的響應(yīng)式屬性曹傀。但是辐脖,可以使用 Vue.set(object, key, value) 方法向嵌套對(duì)象添加響應(yīng)式屬性。例如皆愉,對(duì)于:

                                                                                       JS
var vm = new Vue({
 data: {
   userProfile: {
     name: 'Anika'
   }
 }
})

你可以添加一個(gè)新的 age 屬性到嵌套的 userProfile 對(duì)象:

                                                                                        JS
Vue.set(vm.userProfile, 'age', 27)

你還可以使用 vm.$set 實(shí)例方法嗜价,它只是全局 Vue.set 的別名:

                                                                                        JS
vm.$set(vm.userProfile, 'age', 27)

有時(shí)你可能需要為已有對(duì)象賦予多個(gè)新屬性,比如使用 Object.assign() 或 _.extend()亥啦。在這種情況下炭剪,你應(yīng)該用兩個(gè)對(duì)象的屬性創(chuàng)建一個(gè)新的對(duì)象。所以翔脱,如果你想添加新的響應(yīng)式屬性奴拦,不要像這樣:

                                                                                        JS
Object.assign(vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

你應(yīng)該這樣做:

                                                                                        JS
vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

顯示過(guò)濾/排序結(jié)果

有時(shí),我們想要顯示一個(gè)數(shù)組的過(guò)濾或排序副本届吁,而不實(shí)際改變或重置原始數(shù)據(jù)错妖。在這種情況下,可以創(chuàng)建返回過(guò)濾或排序數(shù)組的計(jì)算屬性疚沐。

例如:

                                                                                        HTML
<li v-for="n in evenNumbers">{{ n }}</li>
                                                                                        JS
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

在計(jì)算屬性不適用的情況下 (例如暂氯,在嵌套 v-for 循環(huán)中) 你可以使用一個(gè) method 方法:

                                                                                        HTML
<li v-for="n in even(numbers)">{{ n }}</li>
                                                                                        JS
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

一段取值范圍的 v-for

v-for 也可以取整數(shù)。在這種情況下亮蛔,它將重復(fù)多次模板痴施。

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

v-for on a <template>

類似于 v-if,你也可以利用帶有 v-for 的 <template> 渲染多個(gè)元素究流。比如:

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

v-for with v-if

當(dāng)它們處于同一節(jié)點(diǎn)辣吃,v-for 的優(yōu)先級(jí)比 v-if 更高,這意味著 v-if 將分別重復(fù)運(yùn)行于每個(gè) v-for 循環(huán)中芬探。當(dāng)你想為僅有的一些項(xiàng)渲染節(jié)點(diǎn)時(shí)神得,這種優(yōu)先級(jí)的機(jī)制會(huì)十分有用,如下:

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

上面的代碼只傳遞了未完成的 todos偷仿。

而如果你的目的是有條件地跳過(guò)循環(huán)的執(zhí)行哩簿,那么可以將 v-if 置于外層元素 (或 <template>)上。如:

                                                                                        HTML
<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

一個(gè)組件的 v-for

在自定義組件里酝静,你可以像任何普通元素一樣用 v-for 节榜。

                                                                                        HTML
<my-component v-for="item in items" :key="item.id"></my-component>
2.2.0+ 的版本里,當(dāng)在組件中使用 v-for 時(shí)别智,key 現(xiàn)在是必須的全跨。

然而,任何數(shù)據(jù)都不會(huì)被自動(dòng)傳遞到組件里亿遂,因?yàn)榻M件有自己獨(dú)立的作用域浓若。為了把迭代數(shù)據(jù)傳遞到組件里渺杉,我們要用 props :

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

不自動(dòng)將 item 注入到組件里的原因是,這會(huì)使得組件與 v-for 的運(yùn)作緊密耦合挪钓。明確組件數(shù)據(jù)的來(lái)源能夠使組件在其他場(chǎng)合重復(fù)使用是越。

下面是一個(gè)簡(jiǎn)單的 todo list 的完整例子:

                                                                                        HTML
<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">Add a todo</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="E.g. Feed the cat"
    >
    <button>Add</button>
  </form>
  <ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:key="todo.id"
      v-bind:title="todo.title"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>

注意這里的 is="todo-item" 屬性。這種做法在使用 DOM 模板時(shí)是十分必要的碌上,因?yàn)樵?<ul> 元素內(nèi)只有 <li> 元素會(huì)被看作有效內(nèi)容倚评。這樣做實(shí)現(xiàn)的效果與 <todo-item> 相同,但是可以避開(kāi)一些潛在的瀏覽器解析錯(cuò)誤馏予。

                                                                                        JS
Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">Remove</button>\
    </li>\
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      {
        id: 1,
        title: 'Do the dishes',
      },
      {
        id: 2,
        title: 'Take out the trash',
      },
      {
        id: 3,
        title: 'Mow the lawn'
      }
    ],
    nextTodoId: 4
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末天梧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子霞丧,更是在濱河造成了極大的恐慌呢岗,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛹尝,死亡現(xiàn)場(chǎng)離奇詭異后豫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)突那,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門挫酿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人愕难,你說(shuō)我怎么就攤上這事早龟。” “怎么了猫缭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵葱弟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我饵骨,道長(zhǎng)翘悉,這世上最難降的妖魔是什么茫打? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任居触,我火速辦了婚禮,結(jié)果婚禮上老赤,老公的妹妹穿的比我還像新娘轮洋。我一直安慰自己,他們只是感情好抬旺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布弊予。 她就那樣靜靜地躺著,像睡著了一般开财。 火紅的嫁衣襯著肌膚如雪汉柒。 梳的紋絲不亂的頭發(fā)上误褪,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音碾褂,去河邊找鬼兽间。 笑死,一個(gè)胖子當(dāng)著我的面吹牛正塌,可吹牛的內(nèi)容都是我干的嘀略。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼乓诽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼帜羊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鸠天,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤讼育,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后粮宛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體窥淆,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年巍杈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了忧饭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筷畦,死狀恐怖词裤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鳖宾,我是刑警寧澤吼砂,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站鼎文,受9級(jí)特大地震影響渔肩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拇惋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一周偎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撑帖,春花似錦蓉坎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春勿侯,著一層夾襖步出監(jiān)牢的瞬間拓瞪,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工助琐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吴藻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓弓柱,卻偏偏與公主長(zhǎng)得像沟堡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矢空,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 條件渲染 v-if 在<template>元素上使用v-if條件渲染分組 最終的渲染結(jié)果將不包含<template...
    oWSQo閱讀 778評(píng)論 1 0
  • 列表循環(huán) v-for 將一個(gè)數(shù)組對(duì)應(yīng)為一組元素 v-for指令根據(jù)數(shù)組選項(xiàng)列表進(jìn)行渲染航罗,使用時(shí)需使用item in...
    JunChow520閱讀 3,299評(píng)論 0 1
  • 用 v-for 把一個(gè)數(shù)組 對(duì)應(yīng)為 一組元素 我們使用 v-for 指令根據(jù)數(shù)組的列表來(lái)進(jìn)行渲染。v-for指令需...
    XKolento閱讀 614評(píng)論 0 12
  • v-for 我們用 v-for 指令根據(jù)一組數(shù)組的選項(xiàng)列表進(jìn)行渲染屁药。 v-for 指令需要以 item in it...
    angelwgh閱讀 672評(píng)論 0 0
  • 我對(duì)你沒(méi)有多大的要求粥血,我只希望你能心里有我,有什么就跟我說(shuō)酿箭,不要對(duì)我藏著掖著复亏,不準(zhǔn)欺負(fù)我。我會(huì)對(duì)你好缭嫡,在你打...
    余二家的三小姐閱讀 110評(píng)論 0 0