淺談vue.js中v-for循環(huán)渲染
這兩天學(xué)習(xí)了Vue.js 感覺(jué)v-for循環(huán)渲染這個(gè)地方知識(shí)點(diǎn)挺多的,而且很重要,所以,今天添加一點(diǎn)小筆記。
一、簡(jiǎn)介
vue.js 的循環(huán)渲染是依賴(lài)于 v-for 指令,它能夠根據(jù) vue 的實(shí)例里面的信息,循環(huán)遍歷所需數(shù)據(jù),然后渲染出相應(yīng)的內(nèi)容。它可以遍歷數(shù)組類(lèi)型以及對(duì)象類(lèi)型的數(shù)據(jù),js 里面的數(shù)組本身實(shí)質(zhì)上也是對(duì)象,這里遍歷數(shù)組和對(duì)象的時(shí)候,方式相似但又稍有不同。
(一)遍歷對(duì)象
<div id="app">
<ul>
<li v-for="(val, key, index) in me">{{index}}. {{key}}: {{val}}</li>
</ul>
</div>
...
var vm = new Vue({
el: '#app',
data: {
me: {
name: 'Dale',
age: 22,
sex: 'male',
height: 170
}
}
});
這里,v-for 接收的參數(shù)相對(duì)較復(fù)雜,但是可以分為三個(gè)部分:
(1)括號(hào)及其內(nèi)的遍歷結(jié)果信息(val, key, index)
其中,val 是遍歷得到的屬性值,key 是遍歷得到的屬性名,index 是遍歷次序,這里的 key/index 都是可選參數(shù),如果不需要,這個(gè)指令其實(shí)可以寫(xiě)成 v-for="val in me";
(2)遍歷關(guān)鍵詞 in
in 可以使用 of 替代,官方的說(shuō)法是“它是最接近 JavaScript 迭代器的語(yǔ)法”,但其實(shí)使用上并沒(méi)有任何區(qū)別;
(3)被遍歷對(duì)象 me
me 是綁定在實(shí)例 data屬性上的一個(gè)屬性,實(shí)際上,它是有一個(gè)執(zhí)行環(huán)境的,也即是我們接觸最多的 vue 實(shí)例,模板中,我們?nèi)耘f可以像在 methods 以及計(jì)算屬性中一樣,通過(guò) this 訪問(wèn)到它,這里的 me 其實(shí)就相當(dāng)于 this.me,模板中直接寫(xiě) this.me 也是可行的。
渲染結(jié)果如下:
<div id="app">
<ul>
<li>0. name: Dale</li>
<li>1. age: 22</li>
<li>2. sex: male</li>
<li>3. height: 170</li>
</ul>
</div>
(二)遍歷數(shù)組
<div id="app">
<ul>
<li v-for="(item, index) in items">{{index}}. {{item}}</li>
</ul>
</div>
...
var vm = new Vue({
el: '#app',
data: {
items: ['apple', 'tomato', 'banana', 'watermelon']
}
});
和遍歷對(duì)象相類(lèi)似,最大的不同點(diǎn)在于對(duì)象的 “key” 和 “index” 是一致的,所以這里我們只需要取一個(gè) index 即可,上面代碼的渲染結(jié)果如下:
<div id="app">
<ul>
<li>0. apple</li>
<li>1. tomato</li>
<li>2. banana</li>
<li>3. watermelon</li>
</ul>
</div>
(三)遍歷“整數(shù)”
理論上來(lái)說(shuō),整數(shù)并不是一個(gè)可遍歷的單元,但是 vue 這里相當(dāng)于給我們提供了一個(gè)方便方式來(lái)減少重復(fù)代碼。
<div id="app">
<ul>
<li v-for="n in num">{{n}}</li>
</ul>
</div>
...
var vm = new Vue({
el: '#app',
data: {
num: 3
}
});
渲染結(jié)果如下:
<div id="app">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
二、實(shí)際應(yīng)用
(一)對(duì)象、數(shù)組 & 組件
實(shí)際應(yīng)用過(guò)程中,我們單獨(dú)使用數(shù)組或者對(duì)象去描述我們的數(shù)據(jù)的情況很少,更常見(jiàn)的模式是結(jié)合了數(shù)組和對(duì)象兩部分內(nèi)容:
<div id="app">
<ul class="persons">
<li v-for="person in persons">name: {{person.name}}, age: {{person.age}};</li>
</ul>
</div>
...
var vm = new Vue({
el: '#app',
data: {
persons: [
{
name: 'Dale',
age: 22
},
{
name: 'Tim',
age: 30
},
{
name: 'Rex',
age: 23
}
]
}
});
本質(zhì)上是遍歷的一個(gè)數(shù)組,但是數(shù)組的每個(gè)元素卻是一個(gè)對(duì)象,也就是上面的 person,我們可以通過(guò) [] 以及 . 兩種方式去訪問(wèn)這個(gè)對(duì)象的屬性,比如這里的 name / age,渲染結(jié)果如下:
<div id="app">
<ul class="persons">
<li>name: Dale, age: 22;</li>
<li>name: Tim, age: 30;</li>
<li>name: Rex, age: 23;</li>
</ul>
</div>
實(shí)際上,更加常用且強(qiáng)大的模式,是使用組件與數(shù)組/對(duì)象進(jìn)行組合,操作方式與上面相類(lèi)似。
(二)與 v-if 組合
添加了 v-for 指令的標(biāo)簽,實(shí)際上也可以同時(shí)添加 v-if 指令,但值得注意的是,v-for 的優(yōu)先級(jí)更高,渲染模板時(shí),相當(dāng)于對(duì)每次遍歷的結(jié)果進(jìn)行了一次條件判斷。
<div id="app">
<ul class="persons">
<li v-for="person in persons" v-if="person.age >= 23">name: {{person.name}}, age: {{person.age}};</li>
</ul>
</div>
...
var vm = new Vue({
el: '#app',
data: {
persons: [
{
name: 'Dale',
age: 22
},
{
name: 'Tim',
age: 30
},
{
name: 'Rex',
age: 23
}
]
}
});
這里先遍歷了 persons 的所有元素,然后檢查每次得到的 person 的是否大于或等于 23,是則輸出,否則不輸出,渲染結(jié)果如下:
<div id="app">
<ul class="persons">
<li>name: Tim, age: 30;</li>
<li>name: Rex, age: 23;</li>
</ul>
</div>
如果要讓 v-if 指令的優(yōu)先級(jí)更高,可以考慮在 v-for 指令所綁定的標(biāo)簽的父級(jí)上添加 v-if 指令。
三、注意事項(xiàng)
(一)key
與 v-for 一樣,在不綁定 key 屬性的情況下,vue 默認(rèn)會(huì)重用元素以提高性能,如果不需要它的默認(rèn)行為,顯式綁定一個(gè)唯一的 key 即可。
(二)數(shù)據(jù) -> 視圖更新
vue 的視圖更新是依賴(lài)于 getter/setter 的,如果直接修改、增加、刪除數(shù)組元素,并不會(huì)觸發(fā)視圖的更新。這里 vue 重寫(xiě)了如下方法:
- push
- pop
- shift
- unshift
- splice
- sort
- reverse
當(dāng)通過(guò)它們修改數(shù)據(jù)的時(shí)候,將會(huì)觸發(fā)視圖的更新。
new Vue({
data: {
arr: [1, 2, 3]
}
});
比如上面這種情況,如果我們想要在執(zhí)行 arr 的 push 等方法,因?yàn)?push 是數(shù)組類(lèi)型數(shù)據(jù)從 Array.prototype.push 繼承過(guò)來(lái)的,所以我們一般情況下有兩種實(shí)現(xiàn)方式。
(1)修改 Array.prototype
Array.prototype.push = function () {
console.log(1);
}
([]).push(); // 1
這里我們修改了 Array.prototype 上的 push 方法,但是實(shí)際上,整個(gè) prototype 屬性都可以被重寫(xiě),如 Array.prototype = xxx,這樣做的好處很明顯,在這一處進(jìn)行修改,之后所有的數(shù)組類(lèi)型都可以直接使用這個(gè)重寫(xiě)后的方法,實(shí)現(xiàn)和使用都非常簡(jiǎn)單;但是這樣帶來(lái)的副作用也特別明顯,容易影響到其它的代碼,其它使用這段代碼的地方,除了功能實(shí)現(xiàn)上可能受到影響外,效率上也會(huì)有較大影響,原生 js 的代碼都是經(jīng)過(guò)特殊優(yōu)化的,我們重寫(xiě)實(shí)現(xiàn),效率肯定會(huì)受到影響,最重要的是,如果大家的代碼在同一個(gè)環(huán)境下運(yùn)行,然后都嘗試重寫(xiě)同一個(gè)方法的話,最終結(jié)果不言而喻。
(2)增加自有方法
var arr = [];
arr.push = function () {
console.log(1);
}
arr.push(); // 1
Array.prototype.push.toString(); // "function push() { [native code] }"
這里修改了 arr 的 push 方法, 但是并不涉及 Array.prototype.push,因?yàn)樽x寫(xiě)一個(gè)對(duì)象的屬性/方法的時(shí)候,js 總是先嘗試訪問(wèn) “ownproperty”,也就是 “hasOwnProperty” 所檢測(cè)的內(nèi)容,這里我們姑且將其稱(chēng)為“自有屬性(方法)”。讀取數(shù)據(jù)的時(shí)候,如果沒(méi)有讀取到內(nèi)容,那么 js 會(huì)嘗試向上搜索 __proto__ 上的數(shù)據(jù);寫(xiě)數(shù)據(jù)的時(shí)候,如果有這個(gè)自有屬性,則會(huì)將其覆蓋,如果沒(méi)有,則將其作為自有屬性添加到改對(duì)象上,而不會(huì)嘗試將其添加到 __proto__ 上,這樣的規(guī)則,也是為了防止“子類(lèi)”以外修改“父類(lèi)”的屬性、方法等。這種實(shí)現(xiàn)方式雖然可以避免上面修改 Array.prototype 的一系列缺點(diǎn),但是它的問(wèn)題就更加明顯,因?yàn)槊看蝿?chuàng)建這樣一個(gè)“數(shù)組”,就要重新實(shí)現(xiàn)/綁定這樣一系列方法,它所帶來(lái)的開(kāi)發(fā)效率、性能問(wèn)題不容小覷。
(3)vue 的實(shí)現(xiàn)方式
var arr = [];
new Vue({
data: {
arr: arr
}
});
arr.push.toString(); // "function mutator() {var arguments$1 = arguments;... 這是 vue 自己的實(shí)現(xiàn)
Array.prototype.push.toString(); // "function push() { [native code] }"... 這是瀏覽器原生的實(shí)現(xiàn)
arr.hasOwnProperty('push'); // false 說(shuō)明不是自有屬性
以上說(shuō)明 vue 既不是修改了 Array.prototype.push,又不是修改了自有屬性。但我們通過(guò) instanceof 操作符檢查的時(shí)候,arr 又是 Array 的一個(gè)實(shí)例,那么它到底是怎么弄的實(shí)現(xiàn)的呢?或者說(shuō) vue 的 push 藏在哪兒呢?
var base = [];
var arr = [];
base.push = function () {
console.log(1);
};
arr.__proto__ = base;
arr.push(); // 1
arr.__proto__.push(); // 1
arr.__proto__.push.toString(); // "function push() { [native code] }"
實(shí)際上,vue 是利用了類(lèi)似上面的方式,先創(chuàng)建了一個(gè) Array 的實(shí)例,也就是一個(gè)數(shù)組類(lèi)型的基礎(chǔ)對(duì)象 base,然后為它添加了一個(gè)自有方法 push,最后用 base 覆蓋了需要擴(kuò)展的 arr 對(duì)象的 __proto__ 屬性。

這里需要重寫(xiě) push 等方法的數(shù)組,我們只需要將其 __proto__ 指向 base 數(shù)組,在讀新創(chuàng)建的數(shù)組的 push 的時(shí)候,發(fā)現(xiàn)它并沒(méi)有這樣一個(gè)自有方法,那么它就嘗試讀 __proto__ 上的方法,發(fā)現(xiàn) __proto__ 屬性(也即 base 數(shù)組)上有這樣一個(gè)自有方法,那么它就不必再向上搜索而直接使用 base.push。
通過(guò)這種方式,我們不必為每一個(gè)數(shù)組重寫(xiě)一遍 push 方法,也不必去修改 Array.prototype ,看起來(lái)倒像是一個(gè)兩全其美的方法。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
element-ui 實(shí)現(xiàn)響應(yīng)式導(dǎo)航欄的示例代碼
這篇文章主要介紹了element-ui 實(shí)現(xiàn)響應(yīng)式導(dǎo)航欄的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
Vue中實(shí)現(xiàn)動(dòng)畫(huà)效果的多種方法小結(jié)
平時(shí)我們能在網(wǎng)頁(yè)上看到很多動(dòng)畫(huà)效果,這些效果看起來(lái)就很引人注目,我們是不是也可以在自己的項(xiàng)目中添加一些動(dòng)畫(huà)效果,讓我們的頁(yè)面看起來(lái)更加的高端大氣上檔次,博人眼球,所以本文給大家介紹了Vue中實(shí)現(xiàn)動(dòng)畫(huà)效果的多種方法,需要的朋友可以參考下2024-07-07
vue實(shí)現(xiàn).md文件預(yù)覽功能的兩種方法詳解
這篇文章主要介紹了Vue預(yù)覽.md文件的兩種方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2025-04-04
vue項(xiàng)目啟動(dòng)命令個(gè)人學(xué)習(xí)記錄
最近想要學(xué)習(xí)vue,正好看到資料,如何通過(guò)命令創(chuàng)建vue項(xiàng)目的方法,就留個(gè)筆記,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目啟動(dòng)命令的相關(guān)資料,需要的朋友可以參考下2023-02-02
vue2中watch的用法(通俗易懂,簡(jiǎn)單明了)
這篇文章主要給大家介紹了關(guān)于vue2中watch用法的相關(guān)資料,通過(guò)watch監(jiān)聽(tīng)器,我們可以實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)的變化,并且在數(shù)據(jù)發(fā)生改變時(shí)進(jìn)行相應(yīng)的操作,需要的朋友可以參考下2023-09-09
Vue使用Element實(shí)現(xiàn)增刪改查+打包的步驟
這篇文章主要介紹了Vue使用Element實(shí)現(xiàn)增刪改查+打包的步驟,幫助大家更好的理解和學(xué)習(xí)vue框架,感興趣的朋友可以了解下2020-11-11
vue3中使用vuedraggable實(shí)現(xiàn)拖拽el-tree數(shù)據(jù)分組功能
這篇文章主要介紹了vue3中使用vuedraggable實(shí)現(xiàn)拖拽el-tree數(shù)據(jù)分組功能,可以實(shí)現(xiàn)單個(gè)拖拽、雙擊添加、按住ctrl鍵實(shí)現(xiàn)多個(gè)添加,或者按住shift鍵實(shí)現(xiàn)范圍添加,添加到框中的數(shù)據(jù),還能拖拽排序,需要的朋友可以參考下2024-02-02

