Vue 實例
屬性和方法
-
每個 Vue 實例都會代理其
data
對象里所有的屬性:var data = { a: 1 } var vm = new Vue({ data: data }) vm.a === data.a // -> true // 設置屬性也會影響到原始數據 vm.a = 2 data.a // -> 2 // ... 反之亦然 data.a = 3 vm.a // -> 3
只有被代理的屬性是響應的。在實例創(chuàng)建之后添加新的屬性到實例上盏求,它不會觸發(fā)視圖更新失仁。
Vue 實例暴露了一些有用的實例屬性和方法祈惶。這些屬性和方法都有前綴
$
,以便于代理的數據屬性區(qū)分俏拱。
實例生命周期
-
Vue 實例在其生命周期的不同階段會調用不同的鉤子,如
created
、compiled
健民、ready
、destroy
贫贝。鉤子的this
指向調用它的 Vue 實例秉犹。var vm = new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 實例 console.log('a is: ' + this.a) } }) // -> "a is: 1"
-
生命周期圖示
數據綁定語法
插值
文本
-
處理單次插值,今后的數據變化不引起插值更新稚晚。
<span>This will never change: {{* msg }}</span>
原始的 HTML
-
使用三 Mustache 標簽輸出真的 HTML 字符串崇堵。
<div>{{{ raw_html }}}</div>
內容以 HTML 字符串插入時,**數據綁定將被忽略 **客燕。如果要復用模板片段鸳劳,應當使用 partials
只對可信內容使用 HTML 插值,永不用于用戶提交的內容也搓。
HTML 特性
-
Mustache 標簽也可以用在 HTML 特性 (attribute) 內赏廓。
<div id="item-{{ id }}"></div>
Vue.js 指令和特殊特性內不能用插值。
綁定表達式
JavaScript 表達式
- Vue.js 在數據綁定內支持全功能的 JavaScript 表達式还绘。表達式將在 Vue 實例的作用域內計算楚昭。
- 每個綁定只能包含單個表達式。
過濾器
-
Vue.js 允許在表達式后添加可選的“過濾器”拍顷,以
|
(管道符)指示抚太。{{ message | capitalize }}
管道語法不是 JavaScript 語法,不能在表達式內使用過濾器昔案,只能添加到表達式后邊尿贫。
-
過濾器可以串聯(lián),也可以接受參數踏揣。過濾器函數始終以表達式的值作為第一個參數庆亡。
{{ message | filterA | filterB }} {{ message | filterA 'arg2' arg3 }}
指令
修飾符
-
修飾符是以半角句號
.
開始的特殊后綴,用于表示指令應當以特殊方式綁定捞稿。<a v-bind:href.literal="/a/b/c"></a>
Vue.js 為兩個最常用的指令 v-bind
和 v-on
提供特別版的縮寫:
<!-- v-bind -->
<a v-bind:href="url"></a>
<a :href="url"></a>
<!-- v-on -->
<a v-on:click="doSomething"></a>
<a @click="doSomething"></a>
計算屬性
- 在模板中要使用多余一個表達式的邏輯時又谋,應當使用計算屬性拼缝。
基礎例子
var vm = new Vue({
el: '#example',
data: {
a: 1
},
computed: {
// 一個計算屬性的 getter
b: function () {
// `this` 指向 vm 實例
return this.a + 1
}
}
})
<div id="example">
a={{ a }}, b={{ b }}
</div>
計算 setter
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
- 規(guī)定 setter 之后,調用
vm.fullName = 'John Doe'
時彰亥,setter 會被調用咧七,vm.firstName
和vm.lastName
也會有相應更新。
Class 與 Style 綁定
- 在
v-bind
用于class
和style
時任斋,Vue.js 專門增強了它继阻。表達式的結果類型除了字符串之外,還可以是對象或數組废酷。
綁定 HTML Class
-
class="{{ className }}"
和v-bind:class
的用法瘟檩,二者只能選其一。
對象語法
-
傳遞給
v-bind:class
一個對象澈蟆,以動態(tài)地切換 class 墨辛。注意v-bind:class
指令可以與普通的class
特性共存。<div class="static" v-bind:class="{ 'class-a': isA, 'class-b': isB }"></div>
data: { isA: true, isB: false }
渲染為
<div class="static class-a"></div>
也可以直接綁定數據里的一個對象趴俘。
數組語法
-
把一個數組傳遞給
v-bind:class
背蟆,以應用一個 class 列表。<div v-bind:class="[classA, classB]">
data: { classA: 'class-a', classB: 'class-b' }
渲染為
<div class="class-a class-b"></div>
如果需要根據條件切換列表中的 class 哮幢,可以使用三元表達式带膀。
<div v-bind:class="[classA, isB ? classB : '']">
在 1.0.19+ 中,可以在數組語法中使用對象語法橙垢。
<div v-bind:class="[classA, { classB: isB, classC: isC }]">
綁定內聯(lián)樣式
對象語法
-
v-bind:style
是一個 JavaScript 對象垛叨。其中的 CSS 屬性名可以用駝峰式,也可以用短橫分割命名柜某。不過嗽元,更推薦直接綁定一個樣式對象<div v-bind:style="styleObject"></div>
data: { styleObject: { color: 'red', fontSize: '13px' } }
數組語法
-
v-bind:style
的數組語法還可以將多個樣式對象應用到一個元素上。<div v-bind:style="[styleObjectA, styleObjectB]">
自動添加前綴
- Vue.js 會自動為需要添加廠商前綴的 CSS 屬性添加廠商前綴喂击。
條件渲染
v-if
-
使用
v-if
控制元素切換剂癌。<h1 v-if="ok">Yes</h1> <h1 v-else>No</h1>
template v-if
-
使用
template
元素當做包裝元素,并在上邊使用v-if
翰绊,實現多個元素的切換佩谷。最終渲染結果不會包含這個元素。<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
v-show
-
v-show
與v-if
用法大體一樣监嗜,不同的是有v-show
的元素會始終渲染并保持在 DOM 中?谐檀,其變化只是簡單地切換元素的 CSS 屬性display
。 -
v-show
不支持<template>
語法裁奇。
組件警告
-
將
v-show
用在組件上時桐猬,因為指令的優(yōu)先級v-else
會出現問題。因此應當使用另一個v-show
替換v-else
刽肠。<custom-component v-show="condition"></custom-component> <p v-show="!condition">這可能也是一個組件</p>
v-if vs. v-show
-
v-if
是真實的條件渲染溃肪,因為它會確保條件塊在切換當中合適地銷毀與重建條件塊內的時間監(jiān)聽器和子組件免胃。 -
v-if
具有惰性。如果在初始渲染時條件為假惫撰,則什么也不做杜秸;在條件第一次變?yōu)檎鏁r才開始局部編譯。相比之下v-show
元素始終被編譯并保留润绎。 - 一般來說,
v-if
有更高的切換消耗而v-show
有更高的初始渲染消耗诞挨。因此莉撇,如果需要頻繁切換v-show
較好惶傻,如果在運行時條件不大可能改變v-if
較好棍郎。
列表渲染
v-for
-
在
v-for
塊內我們能完全訪問父組件作用域內的屬性,另有一個特殊變量$index
作為當前數組元素的索引(從 0 開始)银室。<ul id="example-2"> <li v-for="item in items"> {{ parentMessage }} - {{ $index }} - {{ item.message }} </li> </ul>
-
可以為索引指定一個別名(如果
v-for
用于一個對象涂佃,則可以為對象的鍵指定一個別名)<div v-for="(index, item) in items"> {{ index }} {{ item.message }} </div>
從 1.0.17 開始可以使用
of
替代in
以更接近 JavaScript 遍歷器的語法。
template v-for
-
類似于 template
v-if
蜈敢,也可以將v-for
用在<template>
標簽上辜荠,以渲染一個包含多個元素的塊。<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
數組變動檢測
track-by
-
有時需要用全新對象(例如通過 API 調用創(chuàng)建的對象)替換數組抓狭。因為
v-for
默認通過數據對象的特征來決定對已有作用域和 DOM 元素的復用程度伯病,這可能導致重新渲染整個列表。但是否过,如果每個對象都有一個唯一 ID 的屬性午笛,便可以使用track-by
特性給 Vue.js 一個提示,Vue.js 因而能盡可能地復用已有實例苗桂。
假定數據為:{ items: [ { _uid: '88f869d', ... }, { _uid: '7496c10', ... } ] }
然后可以這樣給出提示:
<div v-for="item in items" track-by="_uid"> <!-- content --> </div>
然后在替換數組 items 時药磺,如果 Vue.js 遇到一個包含 _uid: '88f869d' 的新對象,它知道它可以復用這個已有對象的作用域與 DOM 元素煤伟。
track-by $index
- 如果沒有唯一的鍵供追蹤癌佩,可以使用
track-by="$index"
,它強制讓v-for
進入原位更新模式:片段不會被移動便锨,而是簡單地以對應索引的新值刷新驼卖。這種模式也能處理數組中重復的值。 - 這樣做的代價是:DOM 節(jié)點不會再映射數組元素順序的改變鸿秆,不能同步臨時狀態(tài)(比如
<input>
元素的值)以及組件的私有狀態(tài)酌畜。因此**如果v-for
塊包含<input>
元素或子組件,要小心使用track-by="$index"
卿叽。
問題
-
因為 JavaScript 的限制桥胞,Vue.js 不能檢測到下面數組的變化:
- 直接用索引設置元素恳守,如
vm.items[0] = {}
; - 修改數據的長度贩虾,如
vm.items.length = 0
催烘。
- 直接用索引設置元素恳守,如
-
解決問題 1 ,使用 Vue.js 為觀察數組擴展的
$set()
方法缎罢。// 與 `example1.items[0] = ...` 相同伊群,但是能觸發(fā)視圖更新 example1.items.$set(0, { childMsg: 'Changed!'})
解決問題 2 ,使用一個空數組替換
items
即可策精。-
Vue.js 同時為觀察數組擴展了
$remove()
方法舰始,用于從目標數組中查找并刪除元素,而無需使用splice()
咽袜。this.items.$remove(item)
在遍歷一個數組時,如果數組元素是對象并且對象用
Object.freeze()
凍結询刹,要明確指定track-by
谜嫉。在這種情況下如果 Vue.js 不能自動追蹤對象,將會給出一條警告凹联。
對象 v-for
-
可以使用
v-for
遍歷對象沐兰。除了$index
之外,作用域內還可以訪問另外一個特殊變量$key
蔽挠。<ul id="repeat-object" class="demo"> <li v-for="value in object"> {{ $key }} : {{ value }} </li> </ul>
new Vue({ el: '#repeat-object', data: { object: { FirstName: 'John', LastName: 'Doe', Age: 30 } } })
也可以給對象的鍵提供一個別名:
<div v-for="(key, val) in object"> {{ key }} {{ val }} </div>
遍歷對象使用
Object.keys()
的結果遍歷僧鲁,但并不能保證它的結果在不同的 JavaScript 引擎下一致。
值域 v-for
-
v-for
可以接收一個整數象泵,此時它將重復模板數次寞秃。<div> <span v-for="n in 10">{{ n }} </span> </div>
顯示過濾 / 排序的結果
創(chuàng)建一個計算屬性,返回過濾 / 排序過的數組偶惠。
-
使用內置過濾器:
filterBy
和orderBy
(詳見 API)春寿。<div v-for="item in items | filterBy 'hello'">
<ul> <li v-for="user in users | orderBy 'name'"> {{ user.name }} </li> </ul>
方法與事件處理器
方法處理器
<div id="example">
<button v-on:click="greet">Greet</button>
</div>
-
event
是原生 DOM 事件,使用event.target
訪問 DOM 忽孽。
內聯(lián)語句處理器
<div id="example-2">
<button v-on:click="say('hi')">Say Hi</button>
<button v-on:click="say('what')">Say What</button>
</div>
new Vue({
el: '#example-2',
methods: {
say: function (msg) {
alert(msg)
}
}
})
-
如果需要在內聯(lián)語句中訪問原生 DOM 事件绑改,可以使用特殊變量
$event
。<button v-on:click="say('hello!', $event)">Submit</button>
methods: { say: function (msg, event) { // 現在我們可以訪問原生事件對象 event.preventDefault() } }
事件修飾符
- 將方法從處理 DOM 事件中解放出來兄一,只專注于數據邏輯厘线。為此 Vue.js 為
v-on
提供兩個事件修飾符:.prevent
和.stop
。
```
<!-- 阻止單擊事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯(lián) -->
<a v-on:click.stop.prevent="doThat">
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
```
1.0.16 添加了兩個額外的修飾符:
```
<!-- 添加事件偵聽器時使用 capture 模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當事件在該元素本身(而不是子元素)觸發(fā)時觸發(fā)回調 -->
<div v-on:click.self="doThat">...</div>
```
按鍵修飾符
-
Vue.js 允許為
v-on
添加按鍵修飾符出革,同時為常用的 KeyCode 提供了別名造壮。<!-- 只有在 keyCode 是 13 時調用 vm.submit() --> <input v-on:keyup.13="submit">
<!-- 同上 --> <input v-on:keyup.enter="submit"> <!-- 縮寫語法 --> <input @keyup.enter="submit">
-
1.0.17+ 可以自定義按鍵別名。
// 可以使用 @keyup.f1 Vue.directive('on').keyCodes.f1 = 112
為什么在 HTML 中監(jiān)聽事件
- 當一個 ViewModel 被銷毀時,所有的事件處理器都會自動被刪除耳璧。
表單控件綁定
基礎用法
Checkbox
-
多個勾選框成箫,綁定到同一個數組。
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> <span>Checked names: {{ checkedNames | json }}</span>
new Vue({ el: '...', data: { checkedNames: [] } })
-
多選(綁定到一個數組)旨枯。
<select v-model="selected" multiple> <option selected>A</option> <option>B</option> <option>C</option> </select> <br> <span>Selected: {{ selected | json }}</span>
-
動態(tài)選項蹬昌,用
v-for
渲染。<select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> <span>Selected: {{ selected }}</span>
new Vue({ el: '...', data: { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } })
綁定 value
- 對于單選按鈕攀隔,勾選框及選擇框選項皂贩,
v-model
綁定的 value 通常是靜態(tài)字符串(對于勾選框是邏輯值);若想綁定 value 到 Vue 實例的一個動態(tài)屬性上昆汹,可以用v-bind
實現明刷,并且這個屬性的值可以不是字符串。
Checkbox
<input
type="checkbox"
v-model="toggle"
v-bind:true-value="a"
v-bind:false-value="b">
// 當選中時
vm.toggle === vm.a
// 當沒有選中時
vm.toggle === vm.b
Radio
<input type="radio" v-model="pick" v-bind:value="a">
// 當選中時
vm.pick === vm.a
Select Options
<select v-model="selected">
<!-- 對象字面量 -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// 當選中時
typeof vm.selected // -> 'object'
vm.selected.number // -> 123
參數特性
lazy
- 在默認情況下筹煮,
v-model
在input
事件中同步輸入框值與數據,可以添加一個特性lazy
居夹,從而改到在change
事件中同步败潦。
number
- 如果想自動將用戶的輸入轉為 Number 類型(如果原值的轉換結果為 NaN 則返回原值),可以添加一個特性
number
准脂。
<input v-model="age" number>
debounce
-
debounce
設置一個最小的延時劫扒,在每次敲擊之后延時同步輸入框的值與數據沐旨。如果每次更新都要進行高耗操作(例如在輸入提示中 Ajax 請求)纬傲,它較為有用营罢。<input v-model="msg" debounce="500">
-
debounce
參數不會延遲 input 事件:它延遲“寫入”底層數據晕翠。因此在使用debounce
時應當用vm.$watch()
相應數據的變化瞎抛。若想延遲 DOM 事件蚓曼,應當使用 debounce 過濾器祷安。<input @keyup="onKeyup | debounce 500">
過渡
- 應用過渡效果唉地,要在目標元素上使用
transition
特性砾脑。<div v-if="show" transition="my-transition"></div>
-
transition
特性可以與下面資源一起用:v-if
v-show
-
v-for
(只在插入和刪除時觸發(fā)幼驶,使用 vue-animated-list 插件) - 動態(tài)組件
- 在組件的根節(jié)點上,并且被 Vue 實例 DOM 方法(如
vm.$appendTo(el)
)觸發(fā)韧衣。
- 當插入或刪除帶有過渡的元素時盅藻,Vue 將:
- 嘗試以 ID
"my-transition"
查找 JavaScript 過渡鉤子對象 —— 通過Vue.transition(id, hooks)
或transitions
選項注冊。如果找到了畅铭,將在過渡的不同階段調用相應的鉤子氏淑。 - 自動嗅探目標元素是否有 CSS 過渡或動畫,并在合適時添加 / 刪除 CSS 類名硕噩。
- 如果沒有找到 JavaScript 鉤子并且也沒有檢測到 CSS 過渡 / 動畫假残,DOM操作(插入 / 刪除)在下一幀中立即執(zhí)行。
- 嘗試以 ID
CSS 過渡
示例
<div v-if="show" transition="expand">hello</div>
/* 必需 */
.expand-transition {
transition: all .3s ease;
height: 30px;
padding: 10px;
background-color: #eee;
overflow: hidden;
}
/* .expand-enter 定義進入的開始狀態(tài) */
/* .expand-leave 定義離開的結束狀態(tài) */
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}
-
可以在同一元素上通過動態(tài)綁定實現不同的過渡炉擅。
<div v-if="show" :transition="transitionName">hello</div>
new Vue({ el: '...', data: { show: false, transitionName: 'fade' } })
-
可以提供 JavaScript 鉤子守问。
Vue.transition('expand', { beforeEnter: function (el) { el.textContent = 'beforeEnter' }, enter: function (el) { el.textContent = 'enter' }, afterEnter: function (el) { el.textContent = 'afterEnter' }, enterCancelled: function (el) { // handle cancellation }, beforeLeave: function (el) { el.textContent = 'beforeLeave' }, leave: function (el) { el.textContent = 'leave' }, afterLeave: function (el) { el.textContent = 'afterLeave' }, leaveCancelled: function (el) { // handle cancellation } })
過渡的 CSS 類名
- 類名的添加和切換取決于
transition
特性的值匀归,比如transition="fade"
,會有三個 CSS 類名:-
.fade-transition
始終保留在元素上耗帕。 -
.fade-enter
定義進入過渡的開始狀態(tài)穆端,只應用一幀然后立即刪除。 -
.fade-leave
定義離開過渡的結束狀態(tài)仿便。在離開過渡開始時生效体啰,在它結束后刪除。
-
- 如果
transition
特性沒有值嗽仪,類名默認是.v-transition
荒勇,v-enter
,v-leave
闻坚。
自定義過渡類名
- 自定義過渡類名會覆蓋默認的類名沽翔。
顯式聲明 CSS 過渡類型
-
可能希望一個元素同時帶有兩種類型的動畫,此時要顯式的聲明期望 Vue 處理的動畫類型(
animation
或者transition
)窿凤。Vue.transition('bounce', { // 該過渡效果將只偵聽 `animationend` 事件 type: 'animation' })
CSS 動畫
- 在動畫中
v-center
類名在節(jié)點插入 DOM 后不會立即刪除仅偎,而是在animationed
事件觸發(fā)時刪除。
JavaScript 過渡
- 只使用 JavaScript 鉤子雳殊,不用定義任何 CSS 規(guī)則橘沥。當只使用 JavaScript 過渡時,
enter
和leave
鉤子需要調用done
回調夯秃,否則他們將被同步調用座咆,過渡將立即結束。 - 為 JavaScript 過渡顯式聲明
css: false
以使 Vue.js 跳過 CSS 檢測仓洼。
漸進過渡
-
transition
與v-for
一起使用時可以創(chuàng)建漸進式過渡介陶。給過渡元素添加一個特性stagger
、enter-stagger
或leave-stagger
色建〗锫或者提供一個鉤子stagger
、enter-stagger
或leave-stagger
镀岛。<div v-for="item in list" transition="stagger" stagger="100"></div>
Vue.transition('stagger', { stagger: function (index) { // 每個過渡項目增加 50ms 延時 // 但是最大延時限制為 300ms return Math.min(300, index * 50) } })
組件
使用組件
注冊
用
Vue.extend()
創(chuàng)建一個組件構造器弦牡。-
用
Vue.component(tag, constructor)
注冊。var MyComponent = Vue.extend({ // 選項... }) // 全局注冊組件漂羊,tag 為 my-component Vue.component('my-component', MyComponent)
組件在注冊之后驾锰,便可以在父實例的模塊中以自定義元素
<my-component>
的形式使用。注意自定義元素的作用只是作為一個掛載點走越⊥衷ィ可以用實例選項
replace
決定是否替換。
局部注冊
-
可以用實例選項
components
注冊局部組件。var Child = Vue.extend({ /* ... */ }) var Parent = Vue.extend({ template: '...', components: { // <my-component> 只能用在父組件模板內 'my-component': Child } })
注冊語法糖
-
直接傳入選項對象而不是構造器給
Vue.component()
和component
選項赏酥,Vue.js 會在背后自動調用Vue.extend()
喳整。// 在一個步驟中擴展與注冊 Vue.component('my-component', { template: '<div>A custom component!</div>' }) // 局部注冊也可以這么做 var Parent = Vue.extend({ components: { 'my-component': { template: '<div>A custom component!</div>' } } })
組件選項問題
-
傳入 Vue 構造器的多數選項可以用在
Vue.extend()
中,但如果簡單的把一個對象作為data
或el
傳遞給Vue.extend()
var data = { a: 1 } var MyComponent = Vue.extend({ data: data })
MyComponent
所有的實例都會共享同一個data
對象(或者el
對象)裸扶。 -
應當使用一個函數作為
data
選項框都,讓這個函數返回一個新的對象。var MyComponent = Vue.extend({ data: function () { return { a: 1 } } })
模板解析
-
一些 HTML 元素對什么元素可以放在它里面有限制呵晨,比如:
-
a
不能包含其它的交互元素(如按鈕魏保,鏈接) -
ul
和ol
只能直接包含li
-
select
只能包含option
和optgroup
-
table
只能直接包含thead
,tbody
摸屠,tfoot
谓罗,tr
,caption
季二,col
檩咱,colgroup
-
tr
只能直接包含th
和td
。
-
不能依賴自定義組件在瀏覽器驗證之前的展開結果胯舷。
自定義標簽(包括自定義元素和特殊標簽刻蚯,如
<component>
、<template>
? 需纳、<partial>
)不能用在ul
芦倒,select
艺挪,table
等對內部元素有限制的標簽內不翩。-
對于自定義元素,應當使用
is
屬性麻裳。<table> <tr is="my-component"></tr> </table>
-
<template>
不能用在<table>
內口蝠,應當使用<tbody>
,<table>
可以有多個<tbody>
津坑。<table> <tbody v-for="item in items"> <tr>Even row</tr> <tr>Odd row</tr> </tbody> </table>
Props
使用 props 傳遞數據
-
組件實例的作用域是孤立的妙蔗,不能也不應該在子組件的模板內直接引用父組件的數據,可以使用
props
把數據傳遞給子組件疆瑰。Vue.component('child', { // 聲明 props props: ['msg'], // prop 可以用在模板內 // 可以用 `this.msg` 設置 template: '<span>{{ msg }}</span>' })
<child msg="hello!"></child>
camelCase vs. kebab-case
-
名字形式為 camelCase 的 prop 用作特性時眉反,需要轉變?yōu)?kebab-case。
Vue.component('child', { // camelCase in JavaScript props: ['myMessage'], template: '<span>{{ myMessage }}</span>' })
<!-- kebab-case in HTML --> <child my-message="hello!"></child>
動態(tài) Props
-
可以用
v-bind
綁定動態(tài) Props 到父組件的數據穆役。每當父組件數據變化時寸五,也會傳導給子組件。<div> <input v-model="parentMsg"> <br> <child v-bind:my-message="parentMsg"></child> </div>
字面量語法 vs. 動態(tài)語法
-
字面 prop
<!-- 傳遞了一個字符串 "1" --> <comp some-prop="1"></comp>
-
動態(tài) prop (使用動態(tài)語法)
<!-- 傳遞實際的數字 --> <comp :some-prop="1"></comp>
Prop 綁定類型
prop 默認是單向綁定的耿币。當父組件的屬性變化時梳杏,將傳導給子組件。
-
可以使用
.sync
或.once
綁定修飾符 顯式地強制雙向或單次綁定。<!-- 默認為單向綁定 --> <child :msg="parentMsg"></child> <!-- 雙向綁定 --> <child :msg.sync="parentMsg"></child> <!-- 單次綁定 --> <child :msg.once="parentMsg"></child>
雙向綁定會把子組件的
msg
屬性同步回父組件的parentMsg
屬性十性。單次綁定在建立之后不會同步之后的變化叛溢。如果 prop 是一個對象或數組,是按引用傳遞劲适。在子組件內修改它會影響父組件的狀態(tài)楷掉,不管使用哪種綁定類型。
Prop 驗證
-
為 props 加入驗證要求减响,以確保其他人正確使用組件靖诗。 此時 props 的值是一個對象,包含驗證要求支示。
Vue.component('example', { props: { // 基礎類型檢測 (`null` 意思是任何類型都可以) propA: Number, // 多種類型 (1.0.21+) propM: [String, Number], // 必需且是字符串 propB: { type: String, required: true }, // 數字刊橘,有默認值 propC: { type: Number, default: 100 }, // 對象/數組的默認值應當由一個函數返回 propD: { type: Object, default: function () { return { msg: 'hello' } } }, // 指定這個 prop 為雙向綁定 // 如果綁定類型不對將拋出一條警告 propE: { twoWay: true }, // 自定義驗證函數 propF: { validator: function (value) { return value > 10 } }, // 轉換函數(1.0.12 新增) // 在設置值之前轉換值 propG: { coerce: function (val) { return val + '' // 將值轉換為字符串 } }, propH: { coerce: function (val) { return JSON.parse(val) // 將 JSON 字符串轉換為對象 } } } })
當 prop 驗證失敗了,Vue 將拒絕在子組件上設置此值颂鸿,如果使用的是開發(fā)版本會拋出一條警告促绵。
具體可以參閱 Vue.js 的相關文檔。
父子組件通信
父鏈
- 組件可以用
this.$parent
訪問它的父組件嘴纺。根實例的后代可以用this.$root
訪問它败晴。父組件有一個數組this.$children
,包含它所有的子元素栽渴。 - 子組件應當避免直接依賴父組件的數據尖坤,盡量顯式地使用
props
傳遞數據。 - 不要再子組件中修改父組件的狀態(tài)闲擦。
自定義事件
- 每一個 Vue 實例都是一個事件觸發(fā)器慢味。
- 使用
$on()
監(jiān)聽事件; - 使用
$emit()
在它上面觸發(fā)事件墅冷; - 使用
$dispatch()
派發(fā)事件纯路,事件沿著父鏈冒泡; - 使用
$broadcast()
廣播事件寞忿,事件向下傳導給所有的后代驰唬。
- 使用
- 不同于 DOM 事件,Vue 事件在冒泡過程中第一次觸發(fā)回調之后自動停止冒泡腔彰,除非回調明確返回
true
叫编。
使用 v-on 綁定自定義事件
-
在模板中子組件用到的地方聲明事件處理器。
<child v-on:child-msg="handleIt"></child>
子組件索引
-
可以使用
v-ref
為子組件指定一個索引 ID 霹抛。<div id="parent"> <user-profile v-ref:profile></user-profile> </div>
var parent = new Vue({ el: '#parent' }) // 訪問子組件 var child = parent.$refs.profile
v-ref
和v-for
一起用時搓逾,ref 是一個數組或對象,包含相應的子組件上炎。
使用 Slot 分發(fā)內容
- 為了讓組件可以組合(內容分發(fā))恃逻,Vue.js 實現了一個內容分發(fā) API 雏搂,使用特殊的
<slot>
元素作為原始內容的插槽。
編譯作用域
組件作用域:父組件模板的內容在父組件作用域內編譯寇损;子組件模板的內容在子組件作用域內編譯凸郑。
-
以下模板
<child-component> {{ msg }} </child-component>
msg
應當是綁定到父組件的數據(假定someChildProperty
是子組件的屬性)。 -
一個常見的錯誤:
<!-- 無效 --> <child-component v-show="someChildProperty"></child-component>
父組件模板不應該知道子組件的狀態(tài)矛市,應當在子組件模板中這樣做:
Vue.component('child-component', { // 有效芙沥,因為是在正確的作用域內 template: '<div v-show="someChildProperty">Child</div>', data: function () { return { someChildProperty: true } } })
類似地,分發(fā)內容也是在父組件作用域內編譯浊吏。
單個 Slot
父組件的內容將被拋棄而昨,除非子組件模板包含
<slot>
。如果子組件模板只有一個沒有特性的 slot 找田,父組件的整個內容將插到 slot 所在的地方并替換它歌憨。<slot>
標簽的內容視為回退內容,在子組件的作用域內編譯墩衙。當宿主元素為空并且沒有內容供插入時顯示回退內容务嫡。-
一個例子
my-component
組件模板:<div> <h1>This is my component!</h1> <slot> 如果沒有分發(fā)內容則顯示我。 </slot> </div>
父組件模板:
<my-component> <p>This is some original content</p> <p>This is some more original content</p> </my-component>
渲染結果
<div> <h1>This is my component!</h1> <p>This is some original content</p> <p>This is some more original content</p> </div>
具名 Slot
<slot>
元素可以用一個特殊屬性name
來配置如何分發(fā)內容漆改。可以有一個匿名 slot 作為默認 slot心铃。如果沒有默認 slot ,找不到匹配的內容片段將被拋棄挫剑。
-
一個例子
multi-insertion
組件:<div> <slot name="one"></slot> <slot></slot> <slot name="two"></slot> </div>
父組件模板:
<multi-insertion>
<p slot="one">One</p>
<p slot="two">Two</p>
<p>Default A</p>
</multi-insertion>
```
渲染結果:
```
<div>
<p slot="one">One</p>
<p>Default A</p>
<p slot="two">Two</p>
</div>
```
動態(tài)組件
-
多個組件可以使用同一個掛載點去扣,然后動態(tài)地進行切換。使用保留的
<component>
元素樊破,動態(tài)地綁定到它的is
特性愉棱。new Vue({ el: 'body', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
<component :is="currentView"> <!-- 組件在 vm.currentview 變化時改變 --> </component>
keep-alive
-
如果把切換出去的組件保留在內存中,可以保留它的狀態(tài)或避免重新渲染捶码。為此可以添加一個
keep-alive
指令參數:<component :is="currentView" keep-alive> <!-- 非活動組件將被緩存 --> </component>
activate
鉤子
-
控制組件切換這一時段羽氮,可以為切入組件添加
activate
鉤子或链。Vue.component('activate-example', { activate: function (done) { var self = this loadDataAsync(function (data) { self.someData = data done() }) } })
activate
鉤子只作用于動態(tài)組件切換或靜態(tài)組件初始化渲染的過程中惫恼,不作用于使用實例方法手工插入的過程中。
transition-mode
-
transition-mode
特性用于指定兩個動態(tài)組件之間如何過渡澳盐。<!-- 先淡出再淡入 --> <component :is="view" transition="fade" transition-mode="out-in"> </component>
.fade-transition { transition: opacity .3s ease; } .fade-enter, .fade-leave { opacity: 0; }
雜項
-
自定義組件也可以使用
v-for
祈纯,但是不能將數據傳遞給組件,因為其作用域是孤立的叼耙。應當使用 props 傳遞腕窥。<my-component v-for="item in items" :item="item" :index="$index"> </my-component>
異步組件
Vue.js 允許將組件定義為一個工廠函數,動態(tài)地解析組件的定義筛婉。Vue.js 只在組件需要渲染時觸發(fā)工廠函數簇爆,并且把結果緩存起來癞松,用于后面的再次渲染。
-
一個例子
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { resolve({ template: '<div>I am async!</div>' }) }, 1000) })
工廠函數接收一個
resolve
回調入蛆,在收到從服務器下載的組件定義時調用响蓉。也可以調用reject(reason)
指示加載失敗。這里setTimeout
只是為了演示哨毁。怎么獲取組件完全由你決定枫甲。推薦配合使用 Webpack 的代碼分割功能Vue.component('async-webpack-example', function (resolve) { // 這個特殊的 require 語法告訴 webpack // 自動將編譯后的代碼分割成不同的塊, // 這些塊將通過 ajax 請求自動下載扼褪。 require(['./my-async-component'], resolve) })
遞歸組件
-
有
name
選項的組件可以再模板內部遞歸調用自己想幻。var StackOverflow = Vue.extend({ name: 'stack-overflow', template: '<div>' + // 遞歸地調用它自己 '<stack-overflow></stack-overflow>' + '</div>' })
上面組件會導致一個錯誤 “max stack size exceeded”,所以要確保遞歸調用有終止條件话浇。
片段實例
N/A
內聯(lián)模板
-
如果子組件有
inline-template
特性脏毯,組件將把它的內容當做它的模板,而不是分發(fā)內容幔崖。<my-component inline-template> <p>These are compiled as the component's own template</p> <p>Not parent's transclusion content.</p> </my-component>
inline-template
讓模板的作用域難以理解抄沮,并且不能緩存模板編譯結果。最佳實踐是使用template
選項在組件內定義模板岖瑰。
深入響應式原理
[可以查看我的 Vue 2 的 Guide Note]
自定義指令
基礎
- Vue.js 允許用戶通過
Vue.directive(id, definition)
方法注冊一個全局自定義指令叛买,接收兩個參數:指令 ID 和 定義對象。也可以用組件的directive
選項注冊一個局部自定義指令蹋订。
鉤子函數
- 定義對象可以提供幾個鉤子函數:
bind: 只調用一次率挣,在指令第一次綁定到元素上時調用。
update: 在
bind
之后立即以初始值為參數第一次調用露戒,之后每當綁定值變化時調用椒功,參數為新值與舊值。-
unbind: 只調用一次智什,在指令從元素上解綁時調用动漾。
Vue.directive('my-directive', { bind: function () { // 準備工作 // 例如,添加事件處理器或只需要運行一次的高耗任務 }, update: function (newValue, oldValue) { // 值更新時的工作 // 也會以初始值為參數調用一次 }, unbind: function () { // 清理工作 // 例如荠锭,刪除 bind() 添加的事件監(jiān)聽器 } })
<div v-my-directive="someValue"></div>
當只需要
update
函數時旱眯,可以傳入一個函數替代定義對象Vue.directive('my-directive', function (value) { // 這個函數用作 update() })
指令實例屬性
-
所有的鉤子函數將被復制到實際的指令對象中,鉤子內
this
指向這個指令對象证九。這個對象暴露了一些有用的屬性删豺。- el: 指令綁定的元素。
- vm: 擁有該指令的上下文 ViewModel愧怜。
- expression: 指令的表達式呀页,不包括參數和過濾器。
- arg: 指令的參數拥坛。
- name: 指令的名字蓬蝶,不包含前綴尘分。
- modifiers: 一個對象,包含指令的修飾符丸氛。
- descriptor: 一個對象音诫,包含指令的解析結果。
-
一個例子
<div id="demo" v-demo:hello.a.b="msg"></div>
Vue.directive('demo', { bind: function () { console.log('demo bound!') }, update: function (value) { this.el.innerHTML = 'name - ' + this.name + '<br>' + 'expression - ' + this.expression + '<br>' + 'argument - ' + this.arg + '<br>' + 'modifiers - ' + JSON.stringify(this.modifiers) + '<br>' + 'value - ' + value } }) var demo = new Vue({ el: '#demo', data: { msg: 'hello!' } })
結果
name - demo expression - msg argument = hello modifiers - {"b":true,"a":true} value = hello!
字面修飾符
當指令使用了字面修飾符雪位,它的值將按照普通字符串處理并傳遞給
update
方法竭钝。-
普通字符串不能響應數據變化,故
update
方法將只調用一次雹洗。<div v-demo.literal="foo bar baz">
Vue.directive('demo', function (value) { console.log(value) // "foo bar baz" })
元素指令
-
元素指令可以看做一個輕量組件香罐。
Vue.elementDirective('my-directive', { // API 同普通指令 bind: function () { // 操作 this.el... } })
<my-directive></my-directive>
元素指令是終結性的,這意味著时肿,一旦 Vue 遇到一個元素指令庇茫,它將跳過該元素及其子元素 —— 只有該元素指令本身可以操作該元素及其子元素。
高級選項
[正在整理]
自定義過濾器
基礎
-
可以使用全局方法
Vue.filter()
注冊一個自定義過濾器螃成,接收兩個參數: 過濾器 ID 和 過濾器函數旦签。過濾器函數以值為參數,返回轉換后的值寸宏。Vue.filter('reverse', function (value) { return value.split('').reverse().join('') })
-
過濾器函數可以接收任意數量的參數
Vue.filter('wrap', function (value, begin, end) { return begin + value + end })
<!-- 'hello' => 'before hello after' --> <span v-text="message | wrap 'before' 'after'"></span>
雙向過濾器
-
定義一個過濾器宁炫,把來自視圖(
<input>
元素)的值寫回模型之前轉化它。Vue.filter('currencyDisplay', { // model -> view // 在更新 `<input>` 元素之前格式化值 read: function(val) { return '$'+val.toFixed(2) }, // view -> model // 在寫回數據之前格式化值 write: function(val, oldVal) { var number = +val.replace(/[^\d.]/g, '') return isNaN(number) ? 0 : parseFloat(number.toFixed(2)) } })
動態(tài)參數
- 如果過濾器參數沒有用引號包起來氮凝,則它會在當前 vm 作用域內動態(tài)計算羔巢。另外,過濾器函數的
this
始終指向調用它的 vm罩阵。
混合
基礎
-
混合以一種靈活的方式為組件提供分布復用功能竿秆。混合對象可以包含任意的組件選項稿壁。當組件使用了混合對象時幽钢,混合對象的所有選項將被“混入”組件自己的選項中。
// 定義一個混合對象 var myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } } // 定義一個組件傅是,使用這個混合對象 var Component = Vue.extend({ mixins: [myMixin] }) var component = new Component() // -> "hello from mixin!"
選項合并
- 當混合對象與組件包含同名選項時匪燕,這些選項將以適當的策略合并。
- 混合的鉤子將在組件自己的鉤子之前調用落午。
- 注意
Vue.extend()
使用同樣的合并策略谎懦。
全局混合
- 慎用全局混合肚豺,因為它影響到每個創(chuàng)建的 Vue 實例溃斋,包括第三方組件。在大多數情況下吸申,它應當只用于自定義選項梗劫。
自定義選項合并策略
-
如果想用自定義邏輯合并自定義選項享甸,則向
Vue.config.optionMergeStrategies
添加一個函數:Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { // 返回 mergedVal }
對于多數值為對象的選項,可以簡單地使用
methods
所用的合并策略var strategies = Vue.config.optionMergeStrategies strategies.myOption = strategies.methods
插件
開發(fā)插件
[正在整理]
使用插件
-
通過
Vue.use()
全局方法使用插件梳侨。// 調用 `MyPlugin.install(Vue)` Vue.use(MyPlugin)
也可以傳入一個選項對象
Vue.use(MyPlugin, { someOption: true })
雖然對于一些插件蛉威,如果
Vue
是全局變量則自動調用Vue.use()
,但是在模塊環(huán)境中應當始終顯式調用Vue.use()
走哺。
構建大型應用
- 在 Vue 中可以使用諸如 Jade 之類的預處理器蚯嫌。
路由
- vue-router
- 對于簡單的路由邏輯,可以通過監(jiān)聽
hashchange
事件丙躏,并使用動態(tài)組件實現择示。
與服務器通信
狀態(tài)管理
- 使用 store 模式,把所有的 action 放在 store 內晒旅,action 修改 store 的狀態(tài)栅盲。
- 不要在 action 中替換原始的狀態(tài)對象!
- Vuex : Vue's Flux.