Vue 實例
屬性和方法
-
每個 Vue 實例都會代理其
data
對象里所有的屬性:var data = { a: 1 } var vm = new Vue({ data: data }) vm.a === data.a // -> true // 設(shè)置屬性也會影響到原始數(shù)據(jù) vm.a = 2 data.a // -> 2 // ... 反之亦然 data.a = 3 vm.a // -> 3
只有被代理的屬性是響應(yīng)的。在實例創(chuàng)建之后添加新的屬性到實例上,它不會觸發(fā)視圖更新。
Vue 實例暴露了一些有用的實例屬性和方法。這些屬性和方法都有前綴
$
,以便于代理的數(shù)據(jù)屬性區(qū)分。
實例生命周期
-
Vue 實例在其生命周期的不同階段會調(diào)用不同的鉤子,如
created
、compiled
、ready
、destroy
。鉤子的this
指向調(diào)用它的 Vue 實例。var vm = new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 實例 console.log('a is: ' + this.a) } }) // -> "a is: 1"
-
生命周期圖示
數(shù)據(jù)綁定語法
插值
文本
-
處理單次插值,今后的數(shù)據(jù)變化不引起插值更新。
<span>This will never change: {{* msg }}</span>
原始的 HTML
-
使用三 Mustache 標簽輸出真的 HTML 字符串。
<div>{{{ raw_html }}}</div>
內(nèi)容以 HTML 字符串插入時,**數(shù)據(jù)綁定將被忽略 **。如果要復(fù)用模板片段,應(yīng)當使用 partials
只對可信內(nèi)容使用 HTML 插值,永不用于用戶提交的內(nèi)容。
HTML 特性
-
Mustache 標簽也可以用在 HTML 特性 (attribute) 內(nèi)。
<div id="item-{{ id }}"></div>
Vue.js 指令和特殊特性內(nèi)不能用插值。
綁定表達式
JavaScript 表達式
- Vue.js 在數(shù)據(jù)綁定內(nèi)支持全功能的 JavaScript 表達式。表達式將在 Vue 實例的作用域內(nèi)計算。
- 每個綁定只能包含單個表達式。
過濾器
-
Vue.js 允許在表達式后添加可選的“過濾器”,以
|
(管道符)指示。{{ message | capitalize }}
管道語法不是 JavaScript 語法,不能在表達式內(nèi)使用過濾器,只能添加到表達式后邊。
-
過濾器可以串聯(lián),也可以接受參數(shù)。過濾器函數(shù)始終以表達式的值作為第一個參數(shù)。
{{ message | filterA | filterB }} {{ message | filterA 'arg2' arg3 }}
指令
修飾符
-
修飾符是以半角句號
.
開始的特殊后綴,用于表示指令應(yīng)當以特殊方式綁定。<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>
計算屬性
- 在模板中要使用多余一個表達式的邏輯時,應(yīng)當使用計算屬性。
基礎(chǔ)例子
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 之后,調(diào)用
vm.fullName = 'John Doe'
時,setter 會被調(diào)用,vm.firstName
和vm.lastName
也會有相應(yīng)更新。
Class 與 Style 綁定
- 在
v-bind
用于class
和style
時,Vue.js 專門增強了它。表達式的結(jié)果類型除了字符串之外,還可以是對象或數(shù)組。
綁定 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>
也可以直接綁定數(shù)據(jù)里的一個對象。
數(shù)組語法
-
把一個數(shù)組傳遞給
v-bind:class
,以應(yīng)用一個 class 列表。<div v-bind:class="[classA, classB]">
data: { classA: 'class-a', classB: 'class-b' }
渲染為
<div class="class-a class-b"></div>
如果需要根據(jù)條件切換列表中的 class ,可以使用三元表達式。
<div v-bind:class="[classA, isB ? classB : '']">
在 1.0.19+ 中,可以在數(shù)組語法中使用對象語法。
<div v-bind:class="[classA, { classB: isB, classC: isC }]">
綁定內(nèi)聯(lián)樣式
對象語法
-
v-bind:style
是一個 JavaScript 對象。其中的 CSS 屬性名可以用駝峰式,也可以用短橫分割命名。不過,更推薦直接綁定一個樣式對象<div v-bind:style="styleObject"></div>
data: { styleObject: { color: 'red', fontSize: '13px' } }
數(shù)組語法
-
v-bind:style
的數(shù)組語法還可以將多個樣式對象應(yīng)用到一個元素上。<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
,實現(xiàn)多個元素的切換。最終渲染結(jié)果不會包含這個元素。<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
會出現(xiàn)問題。因此應(yīng)當使用另一個v-show
替換v-else
。<custom-component v-show="condition"></custom-component> <p v-show="!condition">這可能也是一個組件</p>
v-if vs. v-show
-
v-if
是真實的條件渲染,因為它會確保條件塊在切換當中合適地銷毀與重建條件塊內(nèi)的時間監(jiān)聽器和子組件。 -
v-if
具有惰性。如果在初始渲染時條件為假,則什么也不做;在條件第一次變?yōu)檎鏁r才開始局部編譯。相比之下v-show
元素始終被編譯并保留。 - 一般來說,
v-if
有更高的切換消耗而v-show
有更高的初始渲染消耗。因此,如果需要頻繁切換v-show
較好,如果在運行時條件不大可能改變v-if
較好。
列表渲染
v-for
-
在
v-for
塊內(nèi)我們能完全訪問父組件作用域內(nèi)的屬性,另有一個特殊變量$index
作為當前數(shù)組元素的索引(從 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>
數(shù)組變動檢測
track-by
-
有時需要用全新對象(例如通過 API 調(diào)用創(chuàng)建的對象)替換數(shù)組。因為
v-for
默認通過數(shù)據(jù)對象的特征來決定對已有作用域和 DOM 元素的復(fù)用程度,這可能導(dǎo)致重新渲染整個列表。但是,如果每個對象都有一個唯一 ID 的屬性,便可以使用track-by
特性給 Vue.js 一個提示,Vue.js 因而能盡可能地復(fù)用已有實例。
假定數(shù)據(jù)為:{ items: [ { _uid: '88f869d', ... }, { _uid: '7496c10', ... } ] }
然后可以這樣給出提示:
<div v-for="item in items" track-by="_uid"> <!-- content --> </div>
然后在替換數(shù)組 items 時,如果 Vue.js 遇到一個包含 _uid: '88f869d' 的新對象,它知道它可以復(fù)用這個已有對象的作用域與 DOM 元素。
track-by $index
- 如果沒有唯一的鍵供追蹤,可以使用
track-by="$index"
,它強制讓v-for
進入原位更新模式:片段不會被移動,而是簡單地以對應(yīng)索引的新值刷新。這種模式也能處理數(shù)組中重復(fù)的值。 - 這樣做的代價是:DOM 節(jié)點不會再映射數(shù)組元素順序的改變,不能同步臨時狀態(tài)(比如
<input>
元素的值)以及組件的私有狀態(tài)。因此**如果v-for
塊包含<input>
元素或子組件,要小心使用track-by="$index"
。
問題
-
因為 JavaScript 的限制,Vue.js 不能檢測到下面數(shù)組的變化:
- 直接用索引設(shè)置元素,如
vm.items[0] = {}
; - 修改數(shù)據(jù)的長度,如
vm.items.length = 0
。
- 直接用索引設(shè)置元素,如
-
解決問題 1 ,使用 Vue.js 為觀察數(shù)組擴展的
$set()
方法。// 與 `example1.items[0] = ...` 相同,但是能觸發(fā)視圖更新 example1.items.$set(0, { childMsg: 'Changed!'})
解決問題 2 ,使用一個空數(shù)組替換
items
即可。-
Vue.js 同時為觀察數(shù)組擴展了
$remove()
方法,用于從目標數(shù)組中查找并刪除元素,而無需使用splice()
。this.items.$remove(item)
在遍歷一個數(shù)組時,如果數(shù)組元素是對象并且對象用
Object.freeze()
凍結(jié),要明確指定track-by
。在這種情況下如果 Vue.js 不能自動追蹤對象,將會給出一條警告。
對象 v-for
-
可以使用
v-for
遍歷對象。除了$index
之外,作用域內(nèi)還可以訪問另外一個特殊變量$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()
的結(jié)果遍歷,但并不能保證它的結(jié)果在不同的 JavaScript 引擎下一致。
值域 v-for
-
v-for
可以接收一個整數(shù),此時它將重復(fù)模板數(shù)次。<div> <span v-for="n in 10">{{ n }} </span> </div>
顯示過濾 / 排序的結(jié)果
創(chuàng)建一個計算屬性,返回過濾 / 排序過的數(shù)組。
-
使用內(nèi)置過濾器:
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 。
內(nèi)聯(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)
}
}
})
-
如果需要在內(nèi)聯(lián)語句中訪問原生 DOM 事件,可以使用特殊變量
$event
。<button v-on:click="say('hello!', $event)">Submit</button>
methods: { say: function (msg, event) { // 現(xiàn)在我們可以訪問原生事件對象 event.preventDefault() } }
事件修飾符
- 將方法從處理 DOM 事件中解放出來,只專注于數(shù)據(jù)邏輯。為此 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ā)回調(diào) -->
<div v-on:click.self="doThat">...</div>
```
按鍵修飾符
-
Vue.js 允許為
v-on
添加按鍵修飾符,同時為常用的 KeyCode 提供了別名。<!-- 只有在 keyCode 是 13 時調(diào)用 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 被銷毀時,所有的事件處理器都會自動被刪除。
表單控件綁定
基礎(chǔ)用法
Checkbox
-
多個勾選框,綁定到同一個數(shù)組。
<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: [] } })
-
多選(綁定到一個數(shù)組)。
<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
實現(xiàn),并且這個屬性的值可以不是字符串。
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
參數(shù)特性
lazy
- 在默認情況下,
v-model
在input
事件中同步輸入框值與數(shù)據(jù),可以添加一個特性lazy
,從而改到在change
事件中同步。
number
- 如果想自動將用戶的輸入轉(zhuǎn)為 Number 類型(如果原值的轉(zhuǎn)換結(jié)果為 NaN 則返回原值),可以添加一個特性
number
。
<input v-model="age" number>
debounce
-
debounce
設(shè)置一個最小的延時,在每次敲擊之后延時同步輸入框的值與數(shù)據(jù)。如果每次更新都要進行高耗操作(例如在輸入提示中 Ajax 請求),它較為有用。<input v-model="msg" debounce="500">
-
debounce
參數(shù)不會延遲 input 事件:它延遲“寫入”底層數(shù)據(jù)。因此在使用debounce
時應(yīng)當用vm.$watch()
相應(yīng)數(shù)據(jù)的變化。若想延遲 DOM 事件,應(yīng)當使用 debounce 過濾器。<input @keyup="onKeyup | debounce 500">
過渡
- 應(yīng)用過渡效果,要在目標元素上使用
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
選項注冊。如果找到了,將在過渡的不同階段調(diào)用相應(yīng)的鉤子。 - 自動嗅探目標元素是否有 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 定義離開的結(jié)束狀態(tài) */
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}
-
可以在同一元素上通過動態(tài)綁定實現(xiàn)不同的過渡。
<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),只應(yīng)用一幀然后立即刪除。 -
.fade-leave
定義離開過渡的結(jié)束狀態(tài)。在離開過渡開始時生效,在它結(jié)束后刪除。
-
- 如果
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
鉤子需要調(diào)用done
回調(diào),否則他們將被同步調(diào)用,過渡將立即結(jié)束。 - 為 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)建一個組件構(gòu)造器。-
用
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> 只能用在父組件模板內(nèi) 'my-component': Child } })
注冊語法糖
-
直接傳入選項對象而不是構(gòu)造器給
Vue.component()
和component
選項,Vue.js 會在背后自動調(diào)用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 構(gòu)造器的多數(shù)選項可以用在
Vue.extend()
中,但如果簡單的把一個對象作為data
或el
傳遞給Vue.extend()
var data = { a: 1 } var MyComponent = Vue.extend({ data: data })
MyComponent
所有的實例都會共享同一個data
對象(或者el
對象)。 -
應(yīng)當使用一個函數(shù)作為
data
選項,讓這個函數(shù)返回一個新的對象。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
。
-
不能依賴自定義組件在瀏覽器驗證之前的展開結(jié)果。
自定義標簽(包括自定義元素和特殊標簽,如
<component>
、<template>
? 、<partial>
)不能用在ul
,select
,table
等對內(nèi)部元素有限制的標簽內(nèi)。-
對于自定義元素,應(yīng)當使用
is
屬性。<table> <tr is="my-component"></tr> </table>
-
<template>
不能用在<table>
內(nèi),應(yīng)當使用<tbody>
,<table>
可以有多個<tbody>
。<table> <tbody v-for="item in items"> <tr>Even row</tr> <tr>Odd row</tr> </tbody> </table>
Props
使用 props 傳遞數(shù)據(jù)
-
組件實例的作用域是孤立的,不能也不應(yīng)該在子組件的模板內(nèi)直接引用父組件的數(shù)據(jù),可以使用
props
把數(shù)據(jù)傳遞給子組件。Vue.component('child', { // 聲明 props props: ['msg'], // prop 可以用在模板內(nèi) // 可以用 `this.msg` 設(shè)置 template: '<span>{{ msg }}</span>' })
<child msg="hello!"></child>
camelCase vs. kebab-case
-
名字形式為 camelCase 的 prop 用作特性時,需要轉(zhuǎn)變?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 到父組件的數(shù)據(jù)。每當父組件數(shù)據(jù)變化時,也會傳導(dǎo)給子組件。<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)語法)
<!-- 傳遞實際的數(shù)字 --> <comp :some-prop="1"></comp>
Prop 綁定類型
prop 默認是單向綁定的。當父組件的屬性變化時,將傳導(dǎo)給子組件。
-
可以使用
.sync
或.once
綁定修飾符 顯式地強制雙向或單次綁定。<!-- 默認為單向綁定 --> <child :msg="parentMsg"></child> <!-- 雙向綁定 --> <child :msg.sync="parentMsg"></child> <!-- 單次綁定 --> <child :msg.once="parentMsg"></child>
雙向綁定會把子組件的
msg
屬性同步回父組件的parentMsg
屬性。單次綁定在建立之后不會同步之后的變化。如果 prop 是一個對象或數(shù)組,是按引用傳遞。在子組件內(nèi)修改它會影響父組件的狀態(tài),不管使用哪種綁定類型。
Prop 驗證
-
為 props 加入驗證要求,以確保其他人正確使用組件。 此時 props 的值是一個對象,包含驗證要求。
Vue.component('example', { props: { // 基礎(chǔ)類型檢測 (`null` 意思是任何類型都可以) propA: Number, // 多種類型 (1.0.21+) propM: [String, Number], // 必需且是字符串 propB: { type: String, required: true }, // 數(shù)字,有默認值 propC: { type: Number, default: 100 }, // 對象/數(shù)組的默認值應(yīng)當由一個函數(shù)返回 propD: { type: Object, default: function () { return { msg: 'hello' } } }, // 指定這個 prop 為雙向綁定 // 如果綁定類型不對將拋出一條警告 propE: { twoWay: true }, // 自定義驗證函數(shù) propF: { validator: function (value) { return value > 10 } }, // 轉(zhuǎn)換函數(shù)(1.0.12 新增) // 在設(shè)置值之前轉(zhuǎn)換值 propG: { coerce: function (val) { return val + '' // 將值轉(zhuǎn)換為字符串 } }, propH: { coerce: function (val) { return JSON.parse(val) // 將 JSON 字符串轉(zhuǎn)換為對象 } } } })
當 prop 驗證失敗了,Vue 將拒絕在子組件上設(shè)置此值,如果使用的是開發(fā)版本會拋出一條警告。
具體可以參閱 Vue.js 的相關(guān)文檔。
父子組件通信
父鏈
- 組件可以用
this.$parent
訪問它的父組件。根實例的后代可以用this.$root
訪問它。父組件有一個數(shù)組this.$children
,包含它所有的子元素。 - 子組件應(yīng)當避免直接依賴父組件的數(shù)據(jù),盡量顯式地使用
props
傳遞數(shù)據(jù)。 - 不要再子組件中修改父組件的狀態(tài)。
自定義事件
- 每一個 Vue 實例都是一個事件觸發(fā)器。
- 使用
$on()
監(jiān)聽事件; - 使用
$emit()
在它上面觸發(fā)事件; - 使用
$dispatch()
派發(fā)事件,事件沿著父鏈冒泡; - 使用
$broadcast()
廣播事件,事件向下傳導(dǎo)給所有的后代。
- 使用
- 不同于 DOM 事件,Vue 事件在冒泡過程中第一次觸發(fā)回調(diào)之后自動停止冒泡,除非回調(diào)明確返回
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 是一個數(shù)組或?qū)ο螅鄳?yīng)的子組件。
使用 Slot 分發(fā)內(nèi)容
- 為了讓組件可以組合(內(nèi)容分發(fā)),Vue.js 實現(xiàn)了一個內(nèi)容分發(fā) API ,使用特殊的
<slot>
元素作為原始內(nèi)容的插槽。
編譯作用域
組件作用域:父組件模板的內(nèi)容在父組件作用域內(nèi)編譯;子組件模板的內(nèi)容在子組件作用域內(nèi)編譯。
-
以下模板
<child-component> {{ msg }} </child-component>
msg
應(yīng)當是綁定到父組件的數(shù)據(jù)(假定someChildProperty
是子組件的屬性)。 -
一個常見的錯誤:
<!-- 無效 --> <child-component v-show="someChildProperty"></child-component>
父組件模板不應(yīng)該知道子組件的狀態(tài),應(yīng)當在子組件模板中這樣做:
Vue.component('child-component', { // 有效,因為是在正確的作用域內(nèi) template: '<div v-show="someChildProperty">Child</div>', data: function () { return { someChildProperty: true } } })
類似地,分發(fā)內(nèi)容也是在父組件作用域內(nèi)編譯。
單個 Slot
父組件的內(nèi)容將被拋棄,除非子組件模板包含
<slot>
。如果子組件模板只有一個沒有特性的 slot ,父組件的整個內(nèi)容將插到 slot 所在的地方并替換它。<slot>
標簽的內(nèi)容視為回退內(nèi)容,在子組件的作用域內(nèi)編譯。當宿主元素為空并且沒有內(nèi)容供插入時顯示回退內(nèi)容。-
一個例子
my-component
組件模板:<div> <h1>This is my component!</h1> <slot> 如果沒有分發(fā)內(nèi)容則顯示我。 </slot> </div>
父組件模板:
<my-component> <p>This is some original content</p> <p>This is some more original content</p> </my-component>
渲染結(jié)果
<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ā)內(nèi)容。可以有一個匿名 slot 作為默認 slot。如果沒有默認 slot ,找不到匹配的內(nèi)容片段將被拋棄。
-
一個例子
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>
```
渲染結(jié)果:
```
<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
-
如果把切換出去的組件保留在內(nèi)存中,可以保留它的狀態(tài)或避免重新渲染。為此可以添加一個
keep-alive
指令參數(shù):<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
,但是不能將數(shù)據(jù)傳遞給組件,因為其作用域是孤立的。應(yīng)當使用 props 傳遞。<my-component v-for="item in items" :item="item" :index="$index"> </my-component>
異步組件
Vue.js 允許將組件定義為一個工廠函數(shù),動態(tài)地解析組件的定義。Vue.js 只在組件需要渲染時觸發(fā)工廠函數(shù),并且把結(jié)果緩存起來,用于后面的再次渲染。
-
一個例子
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { resolve({ template: '<div>I am async!</div>' }) }, 1000) })
工廠函數(shù)接收一個
resolve
回調(diào),在收到從服務(wù)器下載的組件定義時調(diào)用。也可以調(diào)用reject(reason)
指示加載失敗。這里setTimeout
只是為了演示。怎么獲取組件完全由你決定。推薦配合使用 Webpack 的代碼分割功能Vue.component('async-webpack-example', function (resolve) { // 這個特殊的 require 語法告訴 webpack // 自動將編譯后的代碼分割成不同的塊, // 這些塊將通過 ajax 請求自動下載。 require(['./my-async-component'], resolve) })
遞歸組件
-
有
name
選項的組件可以再模板內(nèi)部遞歸調(diào)用自己。var StackOverflow = Vue.extend({ name: 'stack-overflow', template: '<div>' + // 遞歸地調(diào)用它自己 '<stack-overflow></stack-overflow>' + '</div>' })
上面組件會導(dǎo)致一個錯誤 “max stack size exceeded”,所以要確保遞歸調(diào)用有終止條件。
片段實例
N/A
內(nèi)聯(lián)模板
-
如果子組件有
inline-template
特性,組件將把它的內(nèi)容當做它的模板,而不是分發(fā)內(nèi)容。<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
讓模板的作用域難以理解,并且不能緩存模板編譯結(jié)果。最佳實踐是使用template
選項在組件內(nèi)定義模板。
深入響應(yīng)式原理
[可以查看我的 Vue 2 的 Guide Note]
自定義指令
基礎(chǔ)
- Vue.js 允許用戶通過
Vue.directive(id, definition)
方法注冊一個全局自定義指令,接收兩個參數(shù):指令 ID 和 定義對象。也可以用組件的directive
選項注冊一個局部自定義指令。
鉤子函數(shù)
- 定義對象可以提供幾個鉤子函數(shù):
bind: 只調(diào)用一次,在指令第一次綁定到元素上時調(diào)用。
update: 在
bind
之后立即以初始值為參數(shù)第一次調(diào)用,之后每當綁定值變化時調(diào)用,參數(shù)為新值與舊值。-
unbind: 只調(diào)用一次,在指令從元素上解綁時調(diào)用。
Vue.directive('my-directive', { bind: function () { // 準備工作 // 例如,添加事件處理器或只需要運行一次的高耗任務(wù) }, update: function (newValue, oldValue) { // 值更新時的工作 // 也會以初始值為參數(shù)調(diào)用一次 }, unbind: function () { // 清理工作 // 例如,刪除 bind() 添加的事件監(jiān)聽器 } })
<div v-my-directive="someValue"></div>
當只需要
update
函數(shù)時,可以傳入一個函數(shù)替代定義對象Vue.directive('my-directive', function (value) { // 這個函數(shù)用作 update() })
指令實例屬性
-
所有的鉤子函數(shù)將被復(fù)制到實際的指令對象中,鉤子內(nèi)
this
指向這個指令對象。這個對象暴露了一些有用的屬性。- el: 指令綁定的元素。
- vm: 擁有該指令的上下文 ViewModel。
- expression: 指令的表達式,不包括參數(shù)和過濾器。
- arg: 指令的參數(shù)。
- name: 指令的名字,不包含前綴。
- modifiers: 一個對象,包含指令的修飾符。
- descriptor: 一個對象,包含指令的解析結(jié)果。
-
一個例子
<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!' } })
結(jié)果
name - demo expression - msg argument = hello modifiers - {"b":true,"a":true} value = hello!
字面修飾符
當指令使用了字面修飾符,它的值將按照普通字符串處理并傳遞給
update
方法。-
普通字符串不能響應(yīng)數(shù)據(jù)變化,故
update
方法將只調(diào)用一次。<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>
元素指令是終結(jié)性的,這意味著,一旦 Vue 遇到一個元素指令,它將跳過該元素及其子元素 —— 只有該元素指令本身可以操作該元素及其子元素。
高級選項
[正在整理]
自定義過濾器
基礎(chǔ)
-
可以使用全局方法
Vue.filter()
注冊一個自定義過濾器,接收兩個參數(shù): 過濾器 ID 和 過濾器函數(shù)。過濾器函數(shù)以值為參數(shù),返回轉(zhuǎn)換后的值。Vue.filter('reverse', function (value) { return value.split('').reverse().join('') })
-
過濾器函數(shù)可以接收任意數(shù)量的參數(shù)
Vue.filter('wrap', function (value, begin, end) { return begin + value + end })
<!-- 'hello' => 'before hello after' --> <span v-text="message | wrap 'before' 'after'"></span>
雙向過濾器
-
定義一個過濾器,把來自視圖(
<input>
元素)的值寫回模型之前轉(zhuǎn)化它。Vue.filter('currencyDisplay', { // model -> view // 在更新 `<input>` 元素之前格式化值 read: function(val) { return '$'+val.toFixed(2) }, // view -> model // 在寫回數(shù)據(jù)之前格式化值 write: function(val, oldVal) { var number = +val.replace(/[^\d.]/g, '') return isNaN(number) ? 0 : parseFloat(number.toFixed(2)) } })
動態(tài)參數(shù)
- 如果過濾器參數(shù)沒有用引號包起來,則它會在當前 vm 作用域內(nèi)動態(tài)計算。另外,過濾器函數(shù)的
this
始終指向調(diào)用它的 vm。
混合
基礎(chǔ)
-
混合以一種靈活的方式為組件提供分布復(fù)用功能。混合對象可以包含任意的組件選項。當組件使用了混合對象時,混合對象的所有選項將被“混入”組件自己的選項中。
// 定義一個混合對象 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!"
選項合并
- 當混合對象與組件包含同名選項時,這些選項將以適當?shù)牟呗?/strong>合并。
- 混合的鉤子將在組件自己的鉤子之前調(diào)用。
- 注意
Vue.extend()
使用同樣的合并策略。
全局混合
- 慎用全局混合,因為它影響到每個創(chuàng)建的 Vue 實例,包括第三方組件。在大多數(shù)情況下,它應(yīng)當只用于自定義選項。
自定義選項合并策略
-
如果想用自定義邏輯合并自定義選項,則向
Vue.config.optionMergeStrategies
添加一個函數(shù):Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { // 返回 mergedVal }
對于多數(shù)值為對象的選項,可以簡單地使用
methods
所用的合并策略var strategies = Vue.config.optionMergeStrategies strategies.myOption = strategies.methods
插件
開發(fā)插件
[正在整理]
使用插件
-
通過
Vue.use()
全局方法使用插件。// 調(diào)用 `MyPlugin.install(Vue)` Vue.use(MyPlugin)
也可以傳入一個選項對象
Vue.use(MyPlugin, { someOption: true })
雖然對于一些插件,如果
Vue
是全局變量則自動調(diào)用Vue.use()
,但是在模塊環(huán)境中應(yīng)當始終顯式調(diào)用Vue.use()
。
構(gòu)建大型應(yīng)用
- 在 Vue 中可以使用諸如 Jade 之類的預(yù)處理器。
路由
- vue-router
- 對于簡單的路由邏輯,可以通過監(jiān)聽
hashchange
事件,并使用動態(tài)組件實現(xiàn)。
與服務(wù)器通信
狀態(tài)管理
- 使用 store 模式,把所有的 action 放在 store 內(nèi),action 修改 store 的狀態(tài)。
- 不要在 action 中替換原始的狀態(tài)對象!
- Vuex : Vue's Flux.