概述
指令是帶有v-前綴的特殊屬性摊腋,其值限定為單個(gè)表達(dá)式沸版。指令的作用是,當(dāng)表達(dá)式的值發(fā)生改變時(shí)兴蒸,將其產(chǎn)生的連帶影響應(yīng)用到DOM上视粮。
此外,一些指令還可以帶有參數(shù)橙凳,在指令名稱(chēng)之后以冒號(hào)表示蕾殴。從Vue.js 2.6.0版本開(kāi)始,指令的參數(shù)可以是動(dòng)態(tài)參數(shù)岛啸,語(yǔ)法為指令:[JavaScript表達(dá)式]钓觉。
內(nèi)置指令
Vue.js針對(duì)一些常用的頁(yè)面功能提供了以指令來(lái)封裝的使用形式,以HTML元素屬性的方式使用坚踩,這些指令數(shù)量并不是很多荡灾。
v-show
v-show指令根據(jù)表達(dá)式的值的真假,來(lái)顯示或隱藏HTML元素瞬铸。
代碼示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>v-show 指令</title>
</head>
<body>
<div id="app">
<h1 v-show="yes">Yes!</h1>
<h1 v-show="no">No!</h1>
<h1 v-show="age <= 25">Age: {{age}}</h1>
<h1 v-show="name.indexOf('John') >= 0">Name: {{name}}</h1>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
yes: true,
no: false,
age: 18,
name: 'Will John'
}
})
</script>
</body>
</html>
我們用Chrome瀏覽器打開(kāi)上述頁(yè)面批幌,使用開(kāi)發(fā)者工具展開(kāi)div元素,結(jié)果如下圖所示:
從上圖中可以看到嗓节,因?yàn)閿?shù)據(jù)對(duì)象中的no屬性為false荧缘,因此使用v-show指令計(jì)算no表達(dá)式的<h1>元素沒(méi)有顯示;其他表達(dá)式的值計(jì)算都為true赦政,所以這些表達(dá)式所在的<h1>元素都正常顯示了胜宇。
從Chrome瀏覽器的Elements窗口中可以看到,使用v-show指令恢着,元素本身是要被渲染的桐愉,至于顯示與否是通過(guò)設(shè)置css樣式屬性display來(lái)控制的,如果表達(dá)式的值計(jì)算為false掰派,則設(shè)置樣式"display: none"从诲。接下來(lái)切換到Console窗口,修改age屬性的值為28(vm.age = 28)靡羡,然后切換回Elements窗口系洛,如下圖所示:
由此可以進(jìn)一步確認(rèn)v-show指令是通過(guò)css樣式屬性displa來(lái)控制元素的顯示與否俊性。
指令都是在某個(gè)元素上使用,如果要顯示或隱藏多個(gè)元素描扯,其實(shí)并不需要在每個(gè)元素上都使用v-show指令定页。我們可以使用HTML 5新增的<template>元素來(lái)包裹需要切換顯示與隱藏的多個(gè)元素,然后在<template>元素上使用v-show指令绽诚,最終的渲染結(jié)果中是不會(huì)包含<template>元素的典徊。實(shí)際上,<template>元素是被當(dāng)作一個(gè)不可見(jiàn)的包裹元素恩够,主要用于分組的條件判斷和列表渲染卒落。
使用<template>標(biāo)簽實(shí)現(xiàn)多個(gè)元素顯示隱藏
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>v-show 指令</title>
</head>
<body>
<div id="app">
<template v-show="!isLogin">
<form>
<p>username: <input type="text"></p>
<p>password: <input type="password"></p>
</form>
</template>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
isLogin: false
}
})
</script>
</body>
</html>
渲染結(jié)果如圖所示:
v-if / v-else-if / v-else
v-if、v-else-if蜂桶、v-else這三個(gè)指令用于實(shí)現(xiàn)條件判斷儡毕。
1. v-if
v-if指令根據(jù)表達(dá)式的值的真假來(lái)生成或刪除一個(gè)元素。
代碼示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>v-if 指令</title>
</head>
<body>
<div id="app">
<h1 v-if="yes">Yes!</h1>
<h1 v-if="no">No!</h1>
<h1 v-if="age <= 25">Age: {{age}}</h1>
<h1 v-if="name.indexOf('John') >= 0">Name: {{name}}</h1>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
yes: true,
no: false,
age: 18,
name: 'Will John'
}
})
</script>
</body>
</html>
使用Chrome瀏覽器打開(kāi)頁(yè)面扑媚,如下圖所示:
從上圖可以看到腰湾,包含no表達(dá)式(值為false)的<h1>元素并沒(méi)有生成,其他表達(dá)式的值為true的<h1>元素正常生成了钦购。也就是說(shuō)檐盟,v-if指令在HTML元素的顯示與否的實(shí)現(xiàn)機(jī)制上與v-show指令不同,當(dāng)表達(dá)式的值計(jì)算為false時(shí)押桃,v-if指令不會(huì)創(chuàng)建該元素葵萎,只有當(dāng)表達(dá)式的值為true時(shí),v-if指令才會(huì)真正創(chuàng)建該元素唱凯;而v-show指令不管表達(dá)式的值是真是假羡忘,元素本身都會(huì)被創(chuàng)建。
切換到Console窗口磕昼,修改age屬性的值為28(vm.age = 28)卷雕,然后切換回Elements窗口,如下圖所示:
與v-show指令一樣票从,如果v-if需要控制多個(gè)元素的創(chuàng)建或刪除漫雕,可以用<template>元素來(lái)包裹這些元素,然后在<template>元素上使用v-if指令峰鄙。
一般來(lái)說(shuō)浸间,v-if有更高的切換開(kāi)銷(xiāo),而v-show有更高的出事渲染開(kāi)銷(xiāo)吟榴。因此魁蒜,如果需要非常頻繁地切換元素的顯示或隱藏,則使用v-show較好;如果在運(yùn)行時(shí)條件很少改變兜看,則使用v-if較好锥咸。
2. v-else-if / v-else
v-else-if指令是在Vue.js 2.1.0版本中新增的,與v-if一起使用细移,可以實(shí)現(xiàn)互斥的條件判斷搏予。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<span v-if="score >= 85">優(yōu)秀</span>
<span v-else-if="score >= 75">良好</span>
<span v-else-if="score >= 60">及格</span>
<span v-else>不及格</span>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
score: 90
}
})
</script>
</body>
</html>
當(dāng)一個(gè)條件滿足時(shí),后續(xù)的條件都不會(huì)再判斷弧轧。
- 使用時(shí)缔刹,v-else-if和v-else要緊跟在v-if或v-else-if之后
3. 用key管理可復(fù)用的元素
Vue會(huì)盡可能高效地渲染元素,通常會(huì)復(fù)用已有元素而不是從頭開(kāi)始渲染劣针,這么做使Vue渲染效率變得非常高。
不使用key的情況
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>v-if-key</title>
</head>
<body>
<div id="app">
<template v-if="loginType === 'username'">
<label>用戶名:</label>
<input placeholder="請(qǐng)輸入你的用戶名">
</template>
<template v-else>
<label>Email:</label>
<input placeholder="請(qǐng)輸入你的Email">
</template>
<p><button v-on:click="changeLoginType">切換登陸方式</button></p>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
loginType: 'username'
},
methods: {
changeLoginType() {
if (this.loginType === 'username') {
this.loginType = "email"
} else {
this.loginType = "username"
}
}
}
})
</script>
</body>
</html>
使用瀏覽器打開(kāi)上述頁(yè)面亿扁,初始顯示的是用戶名輸入框捺典,可以在其中任意輸入些內(nèi)容,在點(diǎn)擊“切換登陸方式”按鈕后从祝,之前輸入的內(nèi)容會(huì)被保留下來(lái)襟己。如下圖所示:
這是因?yàn)樵趦蓚€(gè)模版中使用了相同的<input>元素,Vue為了提高渲染效率牍陌,復(fù)用了<input>元素擎浴,因此,在切換登陸時(shí)毒涧,<input>不會(huì)被替換掉贮预,僅僅是替換了它的placeholder屬性。
但有時(shí)這并不是我們想要的契讲,我們不希望在Email輸入框中看到之前輸入的用戶名仿吞,這時(shí)我們可以通過(guò)為<input>元素添加一個(gè)具有唯一值的key屬性,來(lái)取消復(fù)用捡偏。
修改上述代碼唤冈,為<input>標(biāo)簽添加key屬性
<template v-if="loginType === 'username'">
<label>用戶名:</label>
<input placeholder="請(qǐng)輸入你的用戶名" key="username-input">
</template>
<template v-else>
<label>Email:</label>
<input placeholder="請(qǐng)輸入你的Email" key="email-input">
</template>
使用瀏覽器再次打開(kāi)該頁(yè)面,可以發(fā)現(xiàn)切換時(shí)银伟,輸入框會(huì)被重新渲染你虹。
v-for
顧名思義,v-for指令就是通過(guò)循環(huán)的方式來(lái)渲染一個(gè)列表彤避,循環(huán)的對(duì)象可以是數(shù)組傅物,也可以是一個(gè)JavaScript對(duì)象。
1. v-for遍歷數(shù)組
表達(dá)式的語(yǔ)法形式為item in times,其中items是源數(shù)據(jù)數(shù)組忠藤,而item則是被迭代的數(shù)組元素的別名
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li v-for="book in books">{{book.title}}</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
books: [
{title: 'Book1'},
{title: 'Book2'},
{title: 'Book3'}
]
}
})
</script>
</body>
</html>
Vue實(shí)例的數(shù)據(jù)對(duì)象中定義了一個(gè)數(shù)組屬性books挟伙,然后在<li>元素上使用v-for指令遍歷該數(shù)組,這將循環(huán)渲染<li>元素。在v-for塊中尖阔,可以訪問(wèn)所有父作用域的屬性贮缅,book是數(shù)組中元素的別名,每次循環(huán)介却,book的值都被重置為數(shù)組當(dāng)前索引的值谴供,在<li>元素內(nèi)部,可以通過(guò)Mustache語(yǔ)法來(lái)引用該變量值齿坷。
最終渲染結(jié)果如下圖:
- v-for指令的表達(dá)式也可以使用of替代in作為分隔符桂肌,它更接近JavaScript迭代器的語(yǔ)法,如<div v-for="item of items"></div>
v-for指令的表達(dá)式還支持一個(gè)可選的參數(shù)作為當(dāng)前項(xiàng)的索引永淌。
修改代碼中的<li>元素
<li v-for="(book, index) in books">{{index}} - {{book.title}}</li>
多個(gè)參數(shù)需要放到圓括號(hào)中崎场,最后的渲染結(jié)果如下圖所示:
2. 數(shù)組更新檢測(cè)
Vue的核心是數(shù)據(jù)與視圖的雙向綁定,為了檢測(cè)數(shù)組中元素的變化遂蛀,以便能及時(shí)將變化反映到視圖中谭跨,Vue對(duì)數(shù)組的下列變異方法(mutation method)進(jìn)行了包裹。
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
我們可以直接使用Chrome瀏覽器的Console窗口輸入下列語(yǔ)句
vm.books.push({title: 'Book4'})
數(shù)組中還有一些非變異方法(non-mutating method)李滴,如filter()螃宙、concat()和slice(),它們不會(huì)改變?cè)紨?shù)組所坯,而總是返回一個(gè)新數(shù)組谆扎。對(duì)于這些方法,要想讓Vue幫我們自動(dòng)更新視圖芹助,可以使用新數(shù)組來(lái)替換原來(lái)的數(shù)組堂湖。
依然是上述代碼,在瀏覽器控制臺(tái)輸入下面的語(yǔ)句
vm.books = vm.books.concat([{title: 'Book5'}, {title: 'Book6'}])
Vue在檢測(cè)到數(shù)組變化時(shí)状土,并不是直接重新渲染整個(gè)列表苗缩,而是最大化地復(fù)用DOM元素,替換的數(shù)組中声诸,含有相同元素的項(xiàng)不會(huì)被重新渲染酱讶,因此可以大膽地使用新數(shù)組來(lái)替換舊數(shù)組,不用擔(dān)心性能問(wèn)題彼乌。
- 要注意的是泻肯,通過(guò)下述方法引起的數(shù)組變動(dòng),Vue不能檢測(cè)到
// 通過(guò)索引直接設(shè)置數(shù)組值
vm.books[0] = {title: 'Book'}
// 修改數(shù)組的長(zhǎng)度
vm.books.length = 1
要解決上述第一類(lèi)問(wèn)題慰照,可以采用下面兩種方式灶挟,這兩種方式都可以實(shí)現(xiàn)vm.books[0] = {...}相同的效果
// 使用Vue的全局set()方法
Vue.set(vm.books, 0, {title: 'BookA'})
// 使用數(shù)組原型的splice()方法
vm.books.splice(0, 1, {title: 'BookB'})
作為替代,也可以使用Vue實(shí)例的$set方法毒租,該方法是全局方法Vue.set的一個(gè)別名
// 使用Vue實(shí)例的$set()方法
vm.$set(vm.books, 0, {title: 'BookC'})
前述第二類(lèi)問(wèn)題也是使用數(shù)組原型的splice()方法來(lái)解決的稚铣,代碼如下
vm.books.splice(1)
由于篇幅有限,本篇文章就先介紹到這里,v-for的更多用法以及其余指令將在下篇文章繼續(xù)介紹惕医。后續(xù)更多內(nèi)容請(qǐng)參考“Vue學(xué)習(xí)——指令(二)”