一、 Vue 介紹
- Vue.js 是一套構(gòu)建用戶界面的漸進(jìn)式 JavaScript 框架
- 可以輕松構(gòu)建 SPA 應(yīng)用程序
- 通過指令擴(kuò)展了 HTML,通過表達(dá)式綁定數(shù)據(jù)到 HTML
- 最大程度上解放了傳統(tǒng) JavaScript 中頻繁的 DOM 操作,讓開發(fā)人員更加專注于業(yè)務(wù)操作
- 通過組件方便模板重用以及增加可維護(hù)性,使得代碼結(jié)構(gòu)更加合理,維護(hù)成本更低
- Vue 的特性:
- MVVM
- 雙向數(shù)據(jù)綁定
- 組件化
- 漸進(jìn)式
通過下面這個(gè)姓名展示的案例我們先來對比下操作 DOM 的繁瑣 與使用 Vue 的簡便:
- 通過操作 DOM 元素實(shí)現(xiàn)
- HTML 頁面和 JS 代碼耦合
- 對DOM元素 id 的依賴高
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
姓氏:<input type="text" id="surname" value="黃">
<br>
名字:<input type="text" id="givenname" value="慧">
<br>
<p id="fullname">黃慧</p>
</div>
<script>
var surname = document.getElementById('surname')
var givenname = document.getElementById('givenname')
var fullname = document.getElementById('fullname')
surname.addEventListener('input', handleTextInput)
givenname.addEventListener('input', handleTextInput)
function handleTextInput() {
fullname.innerHTML = surname.value + givenname.value
console.log(fullname.innerHTML)
}
</script>
</body>
</html>
- 使用 Vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
姓氏:<input type="text" v-model="surname">
<br>
名字:<input type="text" v-model="givenname">
<br>
<p>{{ surname + givenname }}</p>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el:'#app',
data:{
surname:'黃',
givenname:'慧'
}
})
</script>
</body>
</html>
二、 Vue 實(shí)例
Vue 實(shí)例的選項(xiàng)
每個(gè) Vue 應(yīng)用都是通過 Vue 函數(shù)創(chuàng)建一個(gè)新的 Vue 實(shí)例開始的:
var vm = Vue({
// 選項(xiàng)
})
當(dāng)創(chuàng)建一個(gè) Vue 實(shí)例時(shí),你可以傳入一個(gè)選項(xiàng)對象。這篇教程主要描述的就是如何使用這些選項(xiàng)來創(chuàng)建你想要的行為。作為參考,可以在 API 文檔 中瀏覽完整的選項(xiàng)列表。
1. el 選項(xiàng):
- el 提供一個(gè)在頁面上已存在 DOM 元素作為 Vue 實(shí)例的掛載目標(biāo)??梢允?CSS 選擇器(
new Vue(el: '#app' //其他選項(xiàng))),也可以是一個(gè) HTMLElement 實(shí)例(el: 'document.getElementById('app')')。 - el 不要作用到 <body> 和 <html> 節(jié)點(diǎn)上
- 也可以通過
實(shí)例.$mount()手動掛載(new Vue({ // 選項(xiàng) }).$mount('#app'))
2. data 選項(xiàng):
- data中的數(shù)據(jù)是響應(yīng)式數(shù)據(jù),即為數(shù)據(jù)驅(qū)動視圖,當(dāng)數(shù)據(jù)改變,那么所有綁定該數(shù)據(jù)的 DOM 都會跟著改變
- 可以通過
vm.$data訪問原始數(shù)據(jù)對象 - Vue 實(shí)例也代理了 data 對象上的所有屬性,因此訪問
vm.a等價(jià)于vm.$data.a - 視圖中綁定的數(shù)據(jù)必須顯式的初始化到 data 中,data 外只能修改,不能動態(tài)添加
3. methods 選項(xiàng):
- methods 將被混入到 Vue 實(shí)例中。可以直接通過 VM 實(shí)例訪問這些方法,或者在指令表達(dá)式中使用。方法中的 this 自動綁定為 Vue 實(shí)例。
- 不應(yīng)該使用箭頭函數(shù)來定義 method 函數(shù) (例如
plus: () => this.a++)。理由是箭頭函數(shù)綁定了父級作用域的上下文,所以 this 將不會按照期望指向 Vue 實(shí)例,this.a 將是 undefined。 - 在 data 中定義的方法和在 methods 中定義的箭頭函數(shù) this 都指向 window 實(shí)例,而不是 Vue 實(shí)例
- methods 中的方法定義推薦使用 ES6 的對象屬性函數(shù)簡寫方式,該語法沒有任何特性,只是純粹的簡寫。也就是說:
handleClick: function () {}等價(jià)于handleClick () {}
4. computed 選項(xiàng):
用于定義計(jì)算屬性,詳細(xì)見 四、計(jì)算屬性。
Vue 實(shí)例的生命周期
什么是生命周期?
從 Vue 實(shí)例創(chuàng)建、運(yùn)行、到銷毀期間,總是伴隨著各種各樣的事件,這些事件,統(tǒng)稱為生命周期。
生命周期鉤子
生命周期鉤子 = 生命周期函數(shù) = 生命周期事件
有哪些生命周期函數(shù)?
- 創(chuàng)建期間的生命周期函數(shù):
- beforeCreate:實(shí)例剛在內(nèi)存中被創(chuàng)建出來,此時(shí),還沒有初始化好 data 和 methods 屬性
- created:實(shí)例已經(jīng)在內(nèi)存中創(chuàng)建OK,此時(shí) data 和 methods 已經(jīng)創(chuàng)建OK,此時(shí)還沒有開始編譯模板
- beforeMount:此時(shí)已經(jīng)在內(nèi)存中完成了模板的編譯,但是還沒有掛載到頁面中
- mounted:此時(shí),已經(jīng)將編譯好的模板,掛載到了頁面指定的容器中顯示
- 運(yùn)行期間的生命周期函數(shù):
- beforeUpdate:狀態(tài)更新之前執(zhí)行此函數(shù), 此時(shí) data 中的狀態(tài)值是最新的,但是界面上顯示的數(shù)據(jù)還是舊的,因?yàn)榇藭r(shí)還沒有開始重新渲染DOM節(jié)點(diǎn)
- updated:實(shí)例更新完畢之后調(diào)用此函數(shù),此時(shí) data 中的狀態(tài)值 和 界面上顯示的數(shù)據(jù),都已經(jīng)完成了更新,界面已經(jīng)被重新渲染好了
- 銷毀期間的生命周期函數(shù):
- beforeDestroy:實(shí)例銷毀之前調(diào)用。在這一步,實(shí)例仍然完全可用。
- destroyed:Vue 實(shí)例銷毀后調(diào)用。調(diào)用后,Vue 實(shí)例指示的所有東西都會解綁定,所有的事件監(jiān)聽器會被移除,所有的子實(shí)例也會被銷毀。

三、 數(shù)據(jù)綁定
1. 文本插值
數(shù)據(jù)綁定最常見的形式就是使用 “Mustache” 語法(雙大括號)的文本插值,Mustache 標(biāo)簽將會被替代為對應(yīng)數(shù)據(jù)對象上的 msg 屬性的值。無論何時(shí),綁定的數(shù)據(jù)對象上 msg 屬性發(fā)生了改變,插值處的內(nèi)容都會更新:<span>Message: {{ msg }}</span>
2. 一次性綁定
通過 v-once 指令,執(zhí)行一次性插值,當(dāng)數(shù)據(jù)改變時(shí),插值處的內(nèi)容不會更新。但會影響到該節(jié)點(diǎn)上的其它數(shù)據(jù)綁定:<span v-once>這個(gè)將不會改變: {{ msg }}</span>或<span>這個(gè)將不會改變: {{ *msg }}</span>
3. 輸出 HTML
- 雙大括號會將數(shù)據(jù)解釋為普通文本,而非 HTML 代碼。為了輸出真正的 HTML,可以使用
v-html指令。例如:
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
或者寫成:
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span>{{{ rawHtml }}}</span></p>
結(jié)果:

- 綁定 v-html 指令的 HTML 字符串中不能使用 Vue 的語法特性。
- 你的站點(diǎn)上動態(tài)渲染任意的 HTML 可能會非常危險(xiǎn),因?yàn)樗浅H菀讓?dǎo)致 XSS 攻擊。請只對可信內(nèi)容使用 HTML 插值,絕不要對用戶提供的內(nèi)容使用插值。
4. 屬性綁定
- Mastache 語法不能作用在 HTML 特性上,遇到這種情況應(yīng)該使用 v-bind 指令:
<div v-bind:id="dynamicId"></div> - v-bind 只能用于屬性綁定,它的值(即雙引號里面的值)是一個(gè)JavaScript 表達(dá)式,和
{{}}里面的語法是一致的(語法:加單引號就是字符串,不加是變量或者表達(dá)式)。唯一的區(qū)別就是{{}}用于標(biāo)簽文本綁定,v-bind用于標(biāo)簽屬性綁定。
5. 使用 JavaScript 表達(dá)式
Vue.js 數(shù)據(jù)綁定提供了完全的 JavaScript 表達(dá)式支持
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
- 但是綁定都只能包含單個(gè)表達(dá)式,不能是語句或者流控制,所以下面的例子都不會生效。
<!-- 這是語句,不是表達(dá)式 -->
{{ var a = 1 }}
<!-- 流控制也不會生效,請使用三元表達(dá)式 -->
{{ if (ok) { return message } }}
- 模板表達(dá)式都被放在沙盒中,只能訪問全局變量的一個(gè)白名單,如 Math 和 Date 。你不應(yīng)該在模板表達(dá)式中試圖訪問用戶定義的全局變量。
6. 分隔符
Vue.js 數(shù)據(jù)綁定的語法被設(shè)計(jì)為可配置的。我們可以在 Vue.config 中配置綁定的語法。Vue.config 是一個(gè)對象,包含了 Vue.js 所有的全局配置,可以在 Vue 實(shí)例化前修改其中的屬性。分隔符在 Vue.config 的源碼定義如下:
<!--源碼目錄 src/config.js-->
let delimiters = ['{{','}}']
let unsafeDelimiters = ['{{{','}}}']
delimiters
Vue.config.delimiters = ['<%','%>']可以修改默認(rèn)的文本插值的分隔符,則文本插值的語法由{{ example }}變成<% example %>unsafeDelimiters
Vue.config.unsafeDelimiters = ['<$','$>']可以修改默認(rèn)的 HTML 插值的分隔符,則 HTML 插值的語法由{{{ example }}}變成<$ example $>
四、 指令
指令 (Directives) 是帶有 v- 前綴的特殊特性。指令特性的值預(yù)期是單個(gè) JavaScript 表達(dá)式。指令的職責(zé)是,當(dāng)表達(dá)式的值改變時(shí),將其產(chǎn)生的連帶影響,響應(yīng)式地作用于 DOM。
1. 常用指令
條件渲染指令:
-
v-if- v-if 會根據(jù)條件進(jìn)行渲染和不渲染,true 則渲染 DOM,false 則不渲染 DOM
-
v-else- 使用 v-else 指令來表示 v-if 的“else 塊”
-
v-else-if- 使用 v-else-if 指令來表示 v-if 的“else-if 塊”
- v-else 和 v-else-if 元素必須緊跟在帶 v-if 或者 v-else-if 的元素的后面,否則它將不會被識別。
-
v-show- 帶有 v-show 的元素始終會被渲染并保留在 DOM 中。v-show 只是簡單地切換元素的 CSS 屬性 display
- 在
<template>元素上使用v-if條件渲染分組
因?yàn)?v-if是一個(gè)指令,所以必須將它添加到一個(gè)元素上。但是如果想切換多個(gè)元素呢?此時(shí)可以把一個(gè)<template>元素當(dāng)做不可見的包裹元素,并在上面使用v-if。最終的渲染結(jié)果將不包含<template>元素。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
- 用 key 管理可復(fù)用的元素
這個(gè)例子在本來會復(fù)用的兩個(gè) input 元素上指定不同的 key 。從而告訴 vue 它們是完全獨(dú)立的,不要復(fù)用它們。這樣每次切換時(shí),輸入框都將被重新渲染。
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
v-if和v-show對比,用哪個(gè)?
1.v-if支持 template 語法,v-show不支持。
2. 在切換v-if模塊時(shí), Vue.js 有一個(gè)局部編譯/卸載的過程,因?yàn)?v-if中的模板可能包括數(shù)據(jù)綁定或子組件。v-if是真實(shí)的條件渲染,因?yàn)樗鼤_保條件塊在切換時(shí)合適點(diǎn)的銷毀和重建條件塊內(nèi)部的事件監(jiān)聽器和子組件。v-if是惰性的,如果初始渲染條件為假,則什么也不做,在條件第一次變?yōu)檎鏁r(shí)才開始局部編譯(編譯會被緩存起來)。相比之下v-show簡單的多,元素始終被編譯并保留,只是簡單的基于 CSS 切換。
3.v-if有更高的切換消耗,而v-show有更高的初始渲染消耗。如果需要非常頻繁地切換,則使用v-show較好;如果在運(yùn)行時(shí)條件很少改變,則使用v-if較好。
列表渲染指令:v-for
詳細(xì)參見 五、列表渲染
注冊事件指令:v-on
詳細(xì)參加 五、事件處理
屬性綁定指令: v-bind
只渲染一次指令:v-once
只渲染元素和組件一次。隨后的重新渲染,元素/組件及其所有的子節(jié)點(diǎn)將被視為靜態(tài)內(nèi)容并跳過。這可以用于優(yōu)化更新性能。
綁定輸出 HTML 指令:v-html
表單控件雙向數(shù)據(jù)綁定指令:v-model
參考官網(wǎng):https://cn.vuejs.org/v2/guide/forms.html
只有 v-model 指令即可以實(shí)現(xiàn)數(shù)據(jù)驅(qū)動視圖變化,又可以實(shí)現(xiàn)視圖驅(qū)動數(shù)據(jù)變化的雙向綁定。
-
v-model 指令只能作用于表單元素,可在input、select、text、checkbox、radio 等表單控件上創(chuàng)建雙向數(shù)據(jù)綁定。v-model 在內(nèi)部為不同的輸入元素使用不同的屬性并拋出不同的事件:
- text 和 textarea 元素使用 value 屬性和 input 事件;
- checkbox 和 radio 使用 checked 屬性和 change 事件;
- select 字段將 value 作為 prop 并將 change 作為事件。
-
修飾符:
-
v-model.number: 將用戶輸入值轉(zhuǎn)為數(shù)值類型。
<input v-model.number="age" type="number"> -
v-model.lazy:在默認(rèn)情況下,v-model 在每次 input 事件觸發(fā)后將輸入框的值與數(shù)據(jù)進(jìn)行同步,添加 lazy 修飾符,可以轉(zhuǎn)變?yōu)槭褂?change 事件進(jìn)行同步。
<input v-model.lazy="msg" > -
v-model.trim:輸入首尾空格過濾
<input v-model.trim="msg">
-
數(shù)據(jù)綁定指令:v-text
- 和 {{}} 功能一樣的
- 當(dāng)使用插值表達(dá)式時(shí),由于瀏覽器不認(rèn)識 vue 的插值代表式,只有在瀏覽器加載了vue.js后,執(zhí)行 script 將插值表達(dá)式解析替換為指定的值后,才會顯示出真正的數(shù)據(jù),這樣切換會導(dǎo)致頁面閃爍。v-text指令可以解決插值表達(dá)式閃爍問題。
- 數(shù)據(jù)渲染前樣式指令:
v-cloak這個(gè)指令保持在元素上直到關(guān)聯(lián)實(shí)例結(jié)束編譯。和 CSS 規(guī)則如
[v-cloak] { display: none }一起用時(shí),這個(gè)指令可以隱藏未編譯的 Mustache 標(biāo)簽直到實(shí)例準(zhǔn)備完畢。-
v-cloak 指令也可以解決插值表達(dá)式閃爍問題:
- 使用方法:在頭部加一個(gè)特殊的樣式
[v-cloak] { display: none },然后在被 Vue 管理的模板入口節(jié)點(diǎn)上作用 v-cloak 指令 - 原理:在瀏覽器在解析過程中,發(fā)現(xiàn)具有 v-cloak 的屬性隱藏不顯示,所以就看不見這個(gè) {{}} 閃爍的問題了,當(dāng) Vue 解析替換完之后, Vue 會自動把 v-cloak 樣式移除。
- 使用方法:在頭部加一個(gè)特殊的樣式
加快編譯指令:v-pre
告訴 vue不要解析這個(gè)節(jié)點(diǎn)節(jié)內(nèi)部的內(nèi)容,浪費(fèi)時(shí)間。跳過大量沒有指令的節(jié)點(diǎn)會加快編譯。例如含有大量的網(wǎng)頁文本內(nèi)容節(jié)點(diǎn)可以加這個(gè)指令。
2. 參數(shù)
一些指令能夠接收一個(gè)“參數(shù)”,在指令名稱之后以冒號表示,如:
<a v-bind:href="url">...</a>
<a v-on:click="doSomething">...</a>
3. 指令修飾符
修飾符 (modifier) 是以半角句號 . 指明的特殊后綴,用于指出一個(gè)指令應(yīng)該以特殊方式綁定。例如,.prevent 修飾符告訴 v-on 指令對于觸發(fā)的事件調(diào)用 event.preventDefault():<form v-on:submit.prevent="onSubmit">...</form>
4. 指令縮寫
Vue 為 v-bind 和 v-on 這兩個(gè)最常用的指令,提供了特定簡寫:
- v-bind 縮寫:
<!-- 完整語法 -->
<a v-bind:href="url">...</a>
<!-- 縮寫 -->
<a :href="url">...</a>
- v-on 縮寫:
<!-- 完整語法 -->
<a v-on:click="doSomething">...</a>
<!-- 縮寫 -->
<a @click="doSomething">...</a>
五、列表渲染
v-for 指令的基本用法
- 用
v-for指令基于源數(shù)據(jù)重復(fù)渲染元素。 - v-for 指令需要使用
item in items形式的特殊語法,其中 items 是源數(shù)據(jù)數(shù)組,而 item 則是被迭代的數(shù)組元素的別名。v-for 還支持一個(gè)可選的第二個(gè)參數(shù),即當(dāng)前項(xiàng)的索引,使用(item, index) in items形式的特殊語法。 - 在 v-for 塊中,我們可以訪問所有父作用域的屬性。
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})

- 也可以用 of 替代 in 作為分隔符,因?yàn)樗咏?JavaScript 迭代器的語法:
<div v-for="item of items"></div>。 - 也可以用 v-for 來遍歷一個(gè)對象的屬性。第一個(gè)參數(shù)是對象的值,可以提供第二個(gè)的參數(shù)為 property 名稱 (也就是鍵名),還可以用第三個(gè)參數(shù)作為索引。
<ul id="v-for-object" class="demo">
<li v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})

- 為了給 Vue 一個(gè)提示,以便它能跟蹤每個(gè)節(jié)點(diǎn)的身份,從而重用和重新排序現(xiàn)有元素,你需要為每項(xiàng)提供一個(gè)唯一 key 屬性。建議盡可能在使用 v-for 時(shí)提供 key attribute,除非遍歷輸出的 DOM 內(nèi)容非常簡單,或者是刻意依賴默認(rèn)行為以獲取性能上的提升。
<div v-for="item in items" v-bind:key="item.id">
<!-- 內(nèi)容 -->
</div>
數(shù)組更新檢測
變異方法(mutation method)
我們知道,JS Array 對象有以下變異方法(會改變調(diào)用了這些方法的原始數(shù)組),其 MDN 解釋如下:
- push() - 將一個(gè)或多個(gè)元素添加到數(shù)組的末尾,并返回該數(shù)組的新長度。
- pop() - 從數(shù)組中刪除最后一個(gè)元素,并返回該元素的值。此方法更改數(shù)組的長度。
- shift() - 從數(shù)組中刪除第一個(gè)元素,并返回該元素的值。此方法更改數(shù)組的長度。
- unshift() - 將一個(gè)或多個(gè)元素添加到數(shù)組的開頭,并返回該數(shù)組的新長度。
- splice() - 通過刪除或替換現(xiàn)有元素或者原地添加新的元素來修改數(shù)組,并以數(shù)組形式返回被修改的內(nèi)容。此方法會改變原數(shù)組。
- sort() - 用原地算法對數(shù)組的元素進(jìn)行排序,并返回?cái)?shù)組。排序算法現(xiàn)在是穩(wěn)定的。默認(rèn)排序順序是根據(jù)字符串Unicode碼點(diǎn)。
- reverse() - 將數(shù)組中元素的位置顛倒,并返回該數(shù)組。該方法會改變原數(shù)組。
Vue.js 將被偵聽數(shù)組的變異方法進(jìn)行了包裹,所以在 v-for 循環(huán)數(shù)組進(jìn)行列表渲染時(shí)候如果該數(shù)組調(diào)用了這些方法,會觸發(fā)視圖的重新渲染??梢源蜷_控制臺,然后對前面例子的 items 數(shù)組嘗試調(diào)用變異方法。比如 app.items.push({ message: 'Baz' })
DEMO演示如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Vue-mutation method</title>
</head>
<body>
<ul id="app">
<li v-for="item in items">
{{ item }}
</li>
</ul>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
items: ['March', 'Jan', 'Feb', 'Dec']
}
})
</script>
</body>
</html>

替換數(shù)組
數(shù)組的非變異方法(non-mutating method)不會改變原始數(shù)組,而總是返回一個(gè)新數(shù)組,例如:
- filter() - 創(chuàng)建一個(gè)新數(shù)組, 其包含通過所提供函數(shù)實(shí)現(xiàn)的測試的所有元素。
- slice() - 返回一個(gè)新的數(shù)組對象,這一對象是一個(gè)由 begin和 end(不包括end)決定的原數(shù)組的淺拷貝。原始數(shù)組不會被改變。
- concat() - 用于合并兩個(gè)或多個(gè)數(shù)組。此方法不會更改現(xiàn)有數(shù)組,而是返回一個(gè)新數(shù)組。
當(dāng)使用非變異方法時(shí),可以用新數(shù)組替換舊數(shù)組:
app.items = app.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ù)組去替換原來的數(shù)組是非常高效的操作。
注意事項(xiàng)
由于 JavaScript 的限制,Vue 不能檢測以下數(shù)組的變動:
- 當(dāng)你利用索引直接設(shè)置一個(gè)數(shù)組項(xiàng)時(shí),例如:vm.items[indexOfItem] = newValue
- 當(dāng)你修改數(shù)組的長度時(shí),例如:vm.items.length = newLength
為了解決問題 1,可以用以下兩種方式實(shí)現(xiàn)相同的效果,同時(shí)也將在響應(yīng)式系統(tǒng)內(nèi)觸發(fā)狀態(tài)更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
為了解決問題 2,可以這樣:
vm.items.splice(newLength)
另外,數(shù)組更新檢測除了 Vue.set() (實(shí)例方法又名為vm.$set)方法,還有 Vue.delete (實(shí)例方法又名為 vm.$delete)方法,用于從目標(biāo)數(shù)組中查找并刪除元素。
// Vue.delete
Vue.delete(vm.items, indexOfItem)
// vm.$delete
vm.$delete(vm.items, indexOfItem)
// 也等價(jià)于
vm.items.splice(indexOfItem, 1)

對象更新檢測
注意事項(xiàng)
還是由于 JavaScript 的限制,Vue 不能檢測對象屬性的添加或刪除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 現(xiàn)在是響應(yīng)式的
vm.b = 2
// `vm.b` 不是響應(yīng)式的
對于已經(jīng)創(chuàng)建的實(shí)例,Vue 不允許動態(tài)添加根級別的響應(yīng)式屬性。但是可以使用Vue.set(object, propertyName, value) (或者 vm.$set(object, propertyName, value))方法向嵌套對象添加響應(yīng)式屬性。
有時(shí)你可能需要為已有對象賦值多個(gè)新屬性,比如使用 Object.assign() 或 _.extend()。在這種情況下,你應(yīng)該用兩個(gè)對象的屬性創(chuàng)建一個(gè)新的對象。所以,如果你想添加新的響應(yīng)式屬性,不要像這樣:
Object.assign(vm.object, {
favoriteColor: 'Vue Green'
})
因?yàn)楸磉_(dá)式只會修改vm.userProfile,vm.userProfile仍然指向原引用地址(常用于 合并 對象)
應(yīng)該這樣做:
vm.object= Object.assign({}, vm.object, {
favoriteColor: 'Vue Green'
})
因?yàn)?vm.userProfile 可能是父級組件傳過來的prop,為了遵循單向數(shù)據(jù)流的設(shè)計(jì)理念,不直接修改該數(shù)據(jù)對象,而是生成一個(gè)新的數(shù)據(jù)對象。該表達(dá)式右側(cè)會生成一個(gè)新的對象,vm.userProfile 會指向一個(gè)新的引用地址(常用于 淺拷貝 對象)
Demo :
<ul id="v-for-object" class="demo">
<li v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</li>
</ul>
<script>
const vm = new Vue({
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}).$mount('#v-for-object')




- 在
v-for里使用值范圍
<div>
<span v-for="n in 10">{{ n }} </span>
</div>

- 在
<template>上使用v-for
類似于 v-if,你也可以利用帶有 v-for 的 <template> 來循環(huán)渲染一段包含多個(gè)元素的內(nèi)容。比如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
- 在組件上使用
v-for當(dāng)在組件上使用 v-for 時(shí),key 現(xiàn)在是必須的。如果在組件中使用列表渲染而不提供 key attribute 則 Vue 會出現(xiàn)warning :
component lists rendered with v-for should have explicit keys.任何數(shù)據(jù)都不會被自動傳遞到組件里,因?yàn)榻M件有自己獨(dú)立的作用域。為了把迭代數(shù)據(jù)傳遞到組件里,我們要使用 prop:
<ul id="v-for-component" class="demo">
<my-component
v-for="(value, name, index) in object"
:value="value"
:name="name"
:index="index"
:key="index">
</my-component>
</ul>
<script>
Vue.component('my-component',{
props: ['value','name','index'],
template: `
<li>{{ index }}. {{ name }}: {{ value }}</li>
`
})
const vm = new Vue({
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}).$mount('#v-for-component')
不自動將 item 注入到組件里的原因是,這會使得組件與 v-for 的運(yùn)作緊密耦合。明確組件數(shù)據(jù)的來源能夠使組件在其他場合重復(fù)使用。
注意,由于
<li>只能出現(xiàn)在<ul>列表的內(nèi)部,上述寫法會導(dǎo)致我們使用這些有約束條件的元素時(shí)遇到一些問題潛在的瀏覽器解析錯(cuò)誤,例如,組件的 template 中不含有<li>標(biāo)簽,則會解析報(bào)錯(cuò)。幸好特殊的 is 特性給了我們一個(gè)變通的辦法。
<ul id="v-for-component" class="demo">
<li is="my-component"
v-for="(value, name, index) in object"
:value="value"
:name="name"
:index="index"
:key="index">
</li>
</ul>
六、事件處理
用 v-on 指令可以監(jiān)聽 DOM 事件,并在觸發(fā)時(shí)運(yùn)行一些 JavaScript 代碼。很多事件事件處理邏輯會更為復(fù)雜,直接把 JavaScript 代碼寫在 v-on 指令中是不可行的,因此 v-on 還可以接收一個(gè)需要調(diào)用的方法名稱,該方法定義在 methods 選項(xiàng)中。
v-on綁定方法的兩種方式
-
v-on直接綁定方法(不使用內(nèi)聯(lián)處理器)。
不傳參,該方法天生自帶event 參數(shù),即原生 DOM 代表事件的狀態(tài)的 Event 對象。
直接綁定一個(gè)方法 -
v-on使用內(nèi)聯(lián)處理器綁定方法。
在內(nèi)聯(lián)語句處理器中訪問原始的 DOM 事件,需要將特殊變量 $event 把它傳入方法才能使用原生 DOM 的 event 對象。
內(nèi)聯(lián)語句處理器中訪問 DOM
事件修飾符
在事件處理程序中調(diào)用 event.preventDefault() 或 event.stopPropagation() 是非常常見的需求。盡管我們可以在方法中輕松實(shí)現(xiàn)這點(diǎn),但更好的方式是:方法只有純粹的數(shù)據(jù)邏輯,而不是去處理 DOM 事件細(xì)節(jié)。
為了解決這個(gè)問題,Vue.js 為 v-on 提供了事件修飾符。之前提過,修飾符是由點(diǎn)開頭的指令后綴來表示的。Vue 提供了以下事件修飾符:
-
.stop- 調(diào)用 event.stopPropagation(),阻止事件繼續(xù)傳播。
例如:<a v-on:click.stop="doThis"></a>可以阻止單擊事件繼續(xù)傳播。 -
.prevent- 調(diào)用 event.preventDefault(),阻止事件的默認(rèn)行為。
例如:<form v-on:submit.prevent="onSubmit"></form>提交事件不再重載頁面。 -
.capture- 添加事件監(jiān)聽器時(shí)使用事件捕獲模式。即元素自身觸發(fā)的事件先在此處理,然后才交由內(nèi)部元素進(jìn)行處理 。
例如:<div v-on:click.capture="doThis">...</div> -
.self- 只當(dāng)事件是從偵聽器綁定的元素本身觸發(fā)時(shí)才觸發(fā)回調(diào)。
例如:<div v-on:click.self="doThat">...</div>,只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù),即事件不是從內(nèi)部元素觸發(fā)的。 -
.{keyCode | keyAlias}- 只當(dāng)事件是從特定鍵觸發(fā)時(shí)才觸發(fā)回調(diào)。 -
.native- 監(jiān)聽組件根元素的原生事件。 -
.once- 只觸發(fā)一次回調(diào)。例如:<a v-on:click.once="doThis"></a> -
.left- (2.2.0) 只當(dāng)點(diǎn)擊鼠標(biāo)左鍵時(shí)觸發(fā)。 -
.right- (2.2.0) 只當(dāng)點(diǎn)擊鼠標(biāo)右鍵時(shí)觸發(fā)。 -
.middle- (2.2.0) 只當(dāng)點(diǎn)擊鼠標(biāo)中鍵時(shí)觸發(fā)。 -
.passive- (2.3.0) 以 { passive: true } 模式添加偵聽器
這些事件修飾符還可以串聯(lián),例如:<a v-on:click.stop.prevent="doThat"></a>
Demo演示:
var vm = new Vue({
methods: {
div1Handler() {
console.log('這是觸發(fā)了 inner div 的點(diǎn)擊事件')
},
btnHandler() {
console.log('這是觸發(fā)了 btn 按鈕 的點(diǎn)擊事件')
},
linkClick() {
console.log('觸發(fā)了連接的點(diǎn)擊事件')
},
div2Handler() {
console.log('這是觸發(fā)了 outer div 的點(diǎn)擊事件')
}
}
}).$mount('#app')
- 單擊事件冒泡
<div id="app">
<div class="inner" @click="div1Handler">
<input type="button" value="戳他" @click="btnHandler">
</div>
</div>

- 使用 .stop 阻止冒泡
<div id="app">
<div class="inner" @click="div1Handler">
<input type="button" value="戳他" @click.stop="btnHandler">
</div>
</div>

- 使用 .self 實(shí)現(xiàn)只有點(diǎn)擊當(dāng)前元素時(shí)候,才會觸發(fā)事件處理函數(shù)
<div id="app">
<div class="inner" @click.self="div1Handler">
<input type="button" value="戳他" @click="btnHandler">
</div>
</div>

- 演示: .stop 和 .self 的區(qū)別
<div id="app">
<div class="outer" @click="div2Handler">
<div class="inner" @click="div1Handler">
<input type="button" value="戳他" @click.stop="btnHandler">
</div>
</div>
</div>

.self 只會阻止自己身上冒泡行為的觸發(fā),并不會真正阻止 冒泡的行為:
<div id="app">
<div class="outer" @click="div2Handler">
<div class="inner" @click.self="div1Handler">
<input type="button" value="戳他" @click="btnHandler">
</div>
</div>
</div>

- 使用 .capture 實(shí)現(xiàn)捕獲觸發(fā)事件的機(jī)制
<div id="app">
<div class="inner" @click.capture="div1Handler">
<input type="button" value="戳他" @click="btnHandler">
</div>
</div>

- 單擊觸發(fā)事件默認(rèn)行為
<div id="app">
<a @click="linkClick">有問題,先去百度</a>
</div>

- 使用 .prevent 阻止默認(rèn)行為
<div id="app">
<a @click.prevent="linkClick">有問題,先去百度</a>
</div>

- 使用 .once 只觸發(fā)一次事件處理函數(shù)
<div id="app">
<a @click.prevent.once="linkClick">有問題,先去百度</a>
</div>

使用修飾符時(shí),順序很重要;相應(yīng)的代碼會以同樣的順序產(chǎn)生。因此,用
v-on:click.prevent.self會阻止所有的點(diǎn)擊,而v-on:click.self.prevent只會阻止對元素自身的點(diǎn)擊。
按鍵修飾符
在監(jiān)聽鍵盤事件時(shí),我們經(jīng)常需要檢查詳細(xì)的按鍵。Vue 允許為 v-on 在監(jiān)聽鍵盤事件時(shí)添加按鍵修飾符:
<!-- 只有在 $event.key 是 Enter 時(shí)調(diào)用 vm.submit() -->
<input v-on:keyup.enter="submit">
<!-- 只有在 $event.key 等于 PageDown 時(shí)調(diào)用 vm.onPageDown() -->
<input v-on:keyup.page-down="onPageDown">
使用 keyCode 特性也是允許的:
<input v-on:keyup.13="submit">
Vue 提供了絕大多數(shù)常用的按鍵碼的別名:
.enter.tab-
.delete(捕獲“刪除”和“退格”鍵) .esc.space.up.down.left.right
可以通過全局 config.keyCodes 對象自定義按鍵修飾符別名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
系統(tǒng)修飾鍵
- 可以用如下修飾符來實(shí)現(xiàn)僅在按下相應(yīng)按鍵時(shí)才觸發(fā)鼠標(biāo)或鍵盤事件的監(jiān)聽器。
.ctrl.alt.shift-
.meta:在 Mac 系統(tǒng)鍵盤上,meta 對應(yīng) command 鍵 (?)。在 Windows 系統(tǒng)鍵盤 meta 對應(yīng) Windows 徽標(biāo)鍵 (?)。
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
-
.exact修飾符
.exact 修飾符允許你控制由精確的系統(tǒng)修飾符組合觸發(fā)的事件。
<!-- 即使 Alt 或 Shift 被一同按下時(shí)也會觸發(fā) -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的時(shí)候才觸發(fā) -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 沒有任何系統(tǒng)修飾符被按下的時(shí)候才觸發(fā) -->
<button @click.exact="onClick">A</button>
- 鼠標(biāo)按鍵修飾符
以下修飾符會限制處理函數(shù)僅響應(yīng)特定的鼠標(biāo)按鈕:.left.right.middle
七、計(jì)算屬性和偵聽器
計(jì)算屬性
在模板中放入太多的邏輯會讓模板過重且難以維護(hù),當(dāng)你想要在模板中多次引用此處功能時(shí),就會更加難以處理。例如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
這時(shí)有以下兩個(gè)方案來解決:
- 使用方法把這種復(fù)雜邏輯封裝起來
- 每使用一次就調(diào)用一次,重復(fù)使用效率不高
- 使用計(jì)算屬性
- 不要讓模板邏輯太重
- 解決重復(fù)調(diào)用性能問題
所以,對于任何復(fù)雜邏輯,你都應(yīng)當(dāng)使用計(jì)算屬性。
計(jì)算屬性是 Vue 提供的一大特色,他定義在 computed 選項(xiàng)中。顧名思義,它一種帶有行為的屬性。
計(jì)算屬性和方法的區(qū)別:
- 計(jì)算屬性當(dāng)屬性來使用;方法當(dāng)方法來調(diào)用
- 計(jì)算屬性會緩存計(jì)算的結(jié)果,多次使用也只調(diào)用一次;方法不會緩存結(jié)果,每次使用都會重復(fù)調(diào)用。
- 計(jì)算屬性不能當(dāng)做方法使用,所以不能用于事件處理函數(shù),事件處理函數(shù)還是使用 methods 方法。
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 計(jì)算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 實(shí)例
return this.message.split('').reverse().join('')
}
}
})
我們提供的函數(shù)將用作屬性 vm.reversedMessage 的 getter 函數(shù),也可以這樣寫:
computed: {
// 計(jì)算屬性的 getter
reversedMessage: {
get() {
return this.message.split('').reverse().join('')
}
}
}
Vue 知道 vm.reversedMessage 依賴于 vm.message,因此當(dāng) vm.message 發(fā)生改變時(shí),所有依賴 vm.reversedMessage 的綁定也會重新計(jì)算并更新。
計(jì)算屬性用于進(jìn)行控件渲染的時(shí)候,通??丶沁呌?v-model 進(jìn)行雙向綁定,而計(jì)算屬性定義 get() 和 set() 函數(shù),兩者結(jié)合。
偵聽屬性 watch
Vue 為我們提供了用于監(jiān)視數(shù)據(jù)變化的 watch 選項(xiàng),你可以通過這個(gè)特定根據(jù)數(shù)據(jù)的變化做出對應(yīng)的業(yè)務(wù)處理。當(dāng)需要在數(shù)據(jù)變化執(zhí)行異步或開銷較大時(shí),這個(gè)方法是最為有用的。
引用類型只能監(jiān)視一層,無法監(jiān)視內(nèi)部子成員的改變。如果監(jiān)視數(shù)據(jù)是數(shù)組或者對象需要配置深度 watcher:deep: true
八、Class與Style綁定
參考官網(wǎng):https://cn.vuejs.org/v2/guide/class-and-style.html
操作元素的 class 列表和內(nèi)聯(lián)樣式是數(shù)據(jù)綁定的一個(gè)常見需求。
例如:<h1 class="red thin">Hello World</h1>
因?yàn)樗鼈兌际菍傩?,所以我們可以?v-bind 處理它們:只需要通過表達(dá)式計(jì)算出字符串結(jié)果即可。不過,字符串拼接麻煩且易錯(cuò)。因此,在將 v-bind 用于 class 和 style 時(shí),Vue.js 做了專門的增強(qiáng)。表達(dá)式結(jié)果的類型除了字符串之外,還可以是對象或數(shù)組。
綁定 HTML Class
對象語法
我們可以傳給 v-bind:class 一個(gè)對象,以動態(tài)地切換 class:
例如:
<h1 :class="{ 'red': true, 'thin': true, 'italic': false, 'active': false }">Hello World</h1>
或者:
<h1 :class="classObj">Hello World</h1>
在 data 選項(xiàng)中定義這個(gè)對象,對象的屬性是類名,可帶引號,也可不帶引號:
data: {
classObj: { red: true, thin: true, italic: false, active: false }
}
我們也可以綁定一個(gè)返回對象的計(jì)算屬性。這樣可以根據(jù) data 選項(xiàng)中值來渲染對應(yīng)的樣式。例如:
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
數(shù)組語法
我們可以把一個(gè)數(shù)組傳給 v-bind:class,以應(yīng)用一個(gè) class 列表。
例如:<h1 :class="['thin', 'italic']">Hello World</h1>
如果你也想根據(jù)條件切換列表中的 class,可以用三元表達(dá)式。
例如: <h1 :class="['thin', 'italic', isActive?'active':'']">Hello World</h1>
在數(shù)組語法中也可以使用對象語法,像這樣在數(shù)組中使用對象來代替三元表達(dá)式,可以提高代碼的可讀性。<h1 :class="['thin', 'italic', {'active':isActive} ]">Hello World</h1>
用在組件上
當(dāng)在一個(gè)自定義組件上使用 class 屬性時(shí),這些類將被添加到該組件的根元素上面。這個(gè)元素上已經(jīng)存在的類不會被覆蓋。
例如,如果你聲明了這個(gè)組件:
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
然后在使用它的時(shí)候添加一些 class:
<my-component class="baz boo"></my-component>
HTML 將被渲染為:
<p class="foo bar baz boo">Hi</p>
當(dāng) isActive 為 true 時(shí),HTML 將被渲染成為:
<p class="foo bar active">Hi</p>
綁定內(nèi)聯(lián)樣式
對象語法
v-bind:style 的對象語法十分直觀——看著非常像 CSS,但其實(shí)是一個(gè) JavaScript 對象。CSS 屬性名可以用駝峰式 (camelCase) 或短橫線分隔 (kebab-case,記得用引號括起來) 來命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
直接綁定到一個(gè)樣式對象通常更好,這會讓模板更清晰:
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
同樣的,對象語法常常結(jié)合返回對象的計(jì)算屬性使用。
數(shù)組語法
v-bind:style 的數(shù)組語法可以將多個(gè)樣式對象應(yīng)用到同一個(gè)元素上:
<h1 :style="[ styleObj1, styleObj2 ]">Hello World</h1>
data: {
styleObj1: { color: 'red', 'font-weight': 200 },
styleObj2: { 'font-style': 'italic' }
}
自動添加前綴
當(dāng) v-bind:style 使用需要添加瀏覽器引擎前綴的 CSS 屬性時(shí),如 transform,Vue.js 會自動偵測并添加相應(yīng)的前綴。
九、自定義指令
網(wǎng)址:https://cn.vuejs.org/v2/guide/custom-directive.html
1. What?
除了使用 Vue 提供的內(nèi)置指令(例如 v-model 和 v-show)之外,我們可以自定義一些自己的指令。
2. When?
當(dāng)需要不可避免的操作 DOM 的時(shí)候,使用自定義指令來解決。
3. How?
(1)注冊
- 全局注冊:在任何組件都可以使用全局注冊自定義指令。如果需要在多 個(gè)不同的組件中使用該指令,就把它自定義為全局的。
// 注冊一個(gè)全局自定義指令 `v-focus`
Vue.directive('focus', {
// 當(dāng)被綁定的元素插入到 DOM 中時(shí)……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
參數(shù)說明:
第一個(gè)參數(shù):自定義指令的名字
第二個(gè)參數(shù):配置指令的生命鉤子函數(shù)(當(dāng)符合一定的時(shí)機(jī)調(diào)用的方法叫做鉤子函數(shù))
- 局部注冊:只能在當(dāng)前組件使用該指令。非通用的,不需要多次使用的指令定義到局部。
directives: {
focus: {
// 指令的定義
inserted: function (el) {
el.focus()
}
}
}
(2)使用
<!-- 當(dāng)頁面加載的時(shí)候時(shí),該元素將獲得焦點(diǎn)-->
<input v-focus>
- 自定義指令命名規(guī)則:
- 指令的名字隨便起,但是使用的時(shí)候務(wù)必加上
v-前綴 - 如果是駝峰命名法的名稱,則使用的時(shí)候需要把駝峰轉(zhuǎn)為小寫使用
-連接起來
- 指令的名字隨便起,但是使用的時(shí)候務(wù)必加上
- 全局注冊的自定義指令可以在任何組件中使用
- 組件內(nèi)注冊的自定義指令只能被該組件管理的模板中使用
4. 指令的生命鉤子函數(shù)
(1)一個(gè)指令定義對象可以提供如下幾個(gè)鉤子函數(shù) (均為可選):
bind:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用。在這里可以進(jìn)行一次性的初始化設(shè)置。inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用 (僅保證父節(jié)點(diǎn)存在,但不一定已被插入文檔中)。update:所在組件的 VNode 更新時(shí)調(diào)用,但是可能發(fā)生在其子 VNode 更新之前。指令的值可能發(fā)生了改變,也可能沒有。但是你可以通過比較更新前后的值來忽略不必要的模板更新 (詳細(xì)的鉤子函數(shù)參數(shù)見下)。componentUpdated:指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用。unbind:只調(diào)用一次,指令與元素解綁時(shí)調(diào)用??梢杂脕碜鲆恍?DOM 被移除后的收尾工作,例如清除定時(shí)器。
bind 與 inserted 異同:
相同之處是一上來就執(zhí)行一次,以后再也不會執(zhí)行。
不同之處是 bind 中拿不到父元素,inserted可以拿到父元素。
(如果需要操作指令的父元素,則需要寫到 inserted 中)
update 和 componentUpdated 異同:
相同之處是都是作用該指令的模板發(fā)生更新的時(shí)候會觸發(fā)調(diào)用。
不同之處是update 拿到的是數(shù)據(jù)改變視圖之前的 DOM 內(nèi)容,componentUpdated 拿到的是數(shù)據(jù)改變視圖之后的 DOM 內(nèi)容。
(如果你需要獲取數(shù)據(jù)改變視圖之前的內(nèi)容,則把代碼寫到 update 中; 如果需要獲取數(shù)據(jù)改變視圖之后的內(nèi)容,則把代碼寫到componentUpdated 中)
(2)鉤子函數(shù)的參數(shù) (即 el、binding、vnode 和 oldVnode)。
- el 參數(shù):作用該指令的 DOM 元素
- binding 參數(shù):一個(gè)對象,包含以下屬性:
- name:指令名,不包括 v- 前綴。
- value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值為 2。
- oldValue:指令綁定的前一個(gè)值,僅在 update 和 componentUpdated 鉤子中可用。無論值是否改變都可用。
- expression:字符串形式的指令表達(dá)式。例如 v-my-directive="1 + 1" 中,表達(dá)式為 "1 + 1"。
- arg:傳給指令的參數(shù),可選。例如 v-my-directive:foo 中,參數(shù)為 "foo"。
- modifiers:一個(gè)包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象為 { foo: true, bar: true }。
- vnode 參數(shù):Vue 編譯生成的虛擬節(jié)點(diǎn)。
- oldVnode:上一個(gè)虛擬節(jié)點(diǎn),僅在 update 和 componentUpdated 鉤子中可用。
案例:模擬 v-show 實(shí)現(xiàn),根據(jù)值的真假來顯示或隱藏該指令的元素
只需要在指令第一次綁定到元素時(shí)(bind)和指令對應(yīng)的值更新時(shí)(update)改變該 DOM 元素。
Vue.directive('myShow', {
bind: function (el, binding) {
if(binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
},
update: function (el,binding) {
if(binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
}
})
在很多時(shí)候,你可能想在 bind 和 update 時(shí)觸發(fā)相同行為,而不關(guān)心其它的鉤子。我們可以采取類似以下的簡寫形式來實(shí)現(xiàn)與上面相同的功能。
Vue.directive('myShow', function (el, binding) {
if(binding.value) {
el.style.display = 'block'
} else {
el.style.display = 'none'
}
})
(3)對象字面量
如果指令需要多個(gè)值,可以傳入一個(gè) JavaScript 對象字面量。記住,指令函數(shù)能夠接受所有合法的 JavaScript 表達(dá)式。例如:
HTML:
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
JavaScript:
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
十、過濾器
Vue.js 允許你自定義過濾器,可被用于一些常見的文本格式化。過濾器可以用在兩個(gè)地方:雙花括號插值和 v-bind 表達(dá)式 (后者從 2.1.0+ 開始支持)。
過濾器的定義
全局定義
在創(chuàng)建 Vue 實(shí)例之前全局定義過濾器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
局部定義
可以在一個(gè)組件的選項(xiàng)中定義本地的過濾器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
過濾器的使用
- 過濾器應(yīng)該被添加在 JavaScript 表達(dá)式的尾部,由“管道”符號指示:
<!-- 在雙花括號中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
過濾器函數(shù)總接收表達(dá)式的值 (之前的操作鏈的結(jié)果) 作為第一個(gè)參數(shù)。在上述例子中,capitalize 過濾器函數(shù)將會收到 message 的值作為第一個(gè)參數(shù)。
過濾器可以串聯(lián):
例如:{{ message | filterA | filterB }}
在這個(gè)例子中,filterA 被定義為接收單個(gè)參數(shù)的過濾器函數(shù),表達(dá)式 message 的值將作為參數(shù)傳入到函數(shù)中。然后繼續(xù)調(diào)用同樣被定義為接收單個(gè)參數(shù)的過濾器函數(shù) filterB,將 filterA 的結(jié)果傳遞到 filterB 中。過濾器是 JavaScript 函數(shù),因此可以接收參數(shù):
例如:{{ message | filterA('arg1', arg2) }}
這里,filterA 被定義為接收三個(gè)參數(shù)的過濾器函數(shù)。其中 message 的值作為第一個(gè)參數(shù),普通字符串 'arg1' 作為第二個(gè)參數(shù),表達(dá)式 arg2 的值作為第三個(gè)參數(shù)。過濾器調(diào)用的時(shí)候采用的是就近原則,如果私有過濾器和全局過濾器名稱一致,優(yōu)先調(diào)用私有過濾器。
開發(fā)與調(diào)試
為了方便調(diào)試和觀察 Vue 應(yīng)用,我們可以使用 Vue 官方開發(fā)的一個(gè)瀏覽器插件:Vue Devtools 來輔助調(diào)試。Chrome 商店可以安裝該插件。
使用:
- 在 Web 服務(wù)器中打開你要調(diào)試的 Vue 應(yīng)用
-
打開開發(fā)人員工具,切換到 Vue 面板
Vue Devtools 使用


