這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于 Vue 1.0 ,可以參考我的另一篇文章 Vue.js 1.0 Official Guide Notes。
Vue 實(shí)例
屬性與方法
-
不要在實(shí)例屬性或者回調(diào)函數(shù)中(如
vm.$watch('a', newVal => this.myMethod()))使用箭頭函數(shù)。因?yàn)?strong>箭頭函數(shù)綁定父上下文,所以this不會(huì)像預(yù)想的一樣是Vue實(shí)例,而是this.myMethod未被定義
實(shí)例生命周期
-
生命周期鉤子
var vm = new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 實(shí)例 console.log('a is: ' + this.a) } }) // -> "a is: 1" 也有一些其它的鉤子,在實(shí)例生命周期的不同階段調(diào)用,如
mounted、updated、destroyed。鉤子的this指向調(diào)用它的 Vue 實(shí)例。Vue 沒有 Controller ,組件的自定義邏輯可以分布在這些鉤子中。
生命周期圖示

模板語法
- 在 Vue 2 中,提供了支持 JSX 語法的
render函數(shù)。
插值
文本
-
使用
v-once指令執(zhí)行一次性插值<span v-once>This will never change: {{ msg }}</span>
純 HTML
-
使用
v-html指令輸出純 HTML<div v-html="rawHtml"></div>- 被插入的內(nèi)容都會(huì)被當(dāng)做 HTML ,數(shù)據(jù)綁定會(huì)被忽略。
- 不能使用
v-html來復(fù)合局部模板。 - 只對(duì)可信內(nèi)容使用 HTML 插值,絕不要對(duì)用戶提供的內(nèi)容插值。(避免 XSS )
屬性
-
Mustache 不能在 HTML 屬性中使用,應(yīng)使用
v-bind指令(包括布爾值)。<div v-bind:id="dynamicId"></div>
使用 JavaScript 表達(dá)式
- Vue.js 對(duì)于所有的數(shù)據(jù)綁定都提供了完全的 JavaScript 表達(dá)式支持。
- 每個(gè)綁定只能包含單個(gè)表達(dá)式,不能是語句(比如:賦值語句)也不能是流程控制(使用三元表達(dá)式替代)。
- 模板表達(dá)式被放在沙盒中,只能訪問全局變量的一個(gè)白名單,如
Math和Date。不能模板表達(dá)式中訪問用戶定義的全局變量。
指令
- 指令(Directives)是帶有
v-前綴的特殊屬性。其屬性的值預(yù)期是單一 JavaScript 表達(dá)式(除了v-for)。 - 指令的職責(zé)就是當(dāng)其表達(dá)式的值改變時(shí)相應(yīng)地將某些行為應(yīng)用到 DOM 上。
參數(shù)
- 一些指令能接受一個(gè)“參數(shù)”,在指令后以冒號(hào)指明。
-
v-bind指令被用來響應(yīng)地更新 HTML 屬性:<a v-bind:href="url"></a> -
v-on指令,它用于監(jiān)聽 DOM 事件:<a v-on:click="doSomething">
-
修飾符
- 修飾符(Modifiers)是以半角句號(hào)
.指明的特殊后綴,用于指出一個(gè)指令應(yīng)該以特殊方式綁定。-
.prevent修飾符告訴v-on指令對(duì)于觸發(fā)的事件調(diào)用event.preventDefault():<form v-on:submit.prevent="onSubmit"></form>
-
過濾器
過濾器被用作一些常見的文本格式化。
過濾器可以用在兩個(gè)地方:mustache 插值和
v-bind表達(dá)式。-
過濾器應(yīng)該被添加在 JavaScript 表達(dá)式的尾部,由“管道”符指示。
<!-- in mustaches --> {{ message | capitalize }} <!-- in v-bind --> <div v-bind:id="rawId | formatId"></div> 在 Vue 2 中,過濾器只能在 mustache 綁定和
v-bind表達(dá)式中使用,對(duì)于更復(fù)雜的數(shù)據(jù)變換應(yīng)當(dāng)使用計(jì)算屬性。-
過濾器函數(shù)總接受表達(dá)式的值作為第一個(gè)參數(shù)。
new Vue({ // ... filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } }) -
過濾器可以串聯(lián)。
{{ message | filterA | filterB }} -
過濾器是 JavaScript 函數(shù),因此可以接受參數(shù)。
{{ message | filterA('arg1', arg2) }} // 字符串 'arg1' 將傳給過濾器作為第二個(gè)參數(shù), arg2 表達(dá)式的值將被求值然后傳給過濾器作為第三個(gè)參數(shù)
計(jì)算屬性
計(jì)算屬性
- 在模板中放入太多的邏輯會(huì)讓模板過重且難以維護(hù)。
計(jì)算屬性 vs Methods
對(duì)于最終結(jié)果,計(jì)算屬性與 Method 是相同的。
-
計(jì)算屬性是基于它們的依賴進(jìn)行緩存的,其只有在它的相關(guān)依賴發(fā)生改變時(shí)才會(huì)重新求值。
-
當(dāng)然這也意味著有些計(jì)算屬性求值后將不會(huì)更新,比如
Date.now(),因?yàn)樗皇琼憫?yīng)式依賴。computed: { now: function () { return Date.now() } }
-
相比而言,只要發(fā)生重新渲染,method 調(diào)用總會(huì)執(zhí)行該函數(shù)。
Computed 屬性 vs Watched 屬性
- Computed 屬性能更好的處理多個(gè)數(shù)據(jù)的變動(dòng),而不需要為每一個(gè)數(shù)據(jù)單獨(dú)書寫 watch 函數(shù)。
計(jì)算 setter
-
計(jì)算屬性默認(rèn)只有 getter ,但允許提供 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] } } } // ... 現(xiàn)在在運(yùn)行
vm.fullName = 'John Doe'時(shí), setter 會(huì)被調(diào)用,vm.firstName和vm.lastName也相應(yīng)地會(huì)被更新。
觀察 Watchers
當(dāng)想要在數(shù)據(jù)變化響應(yīng)時(shí),執(zhí)行異步操作或開銷較大的操作,
watch會(huì)很實(shí)用。-
舉個(gè)栗子:
<div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div><!-- Since there is already a rich ecosystem of ajax libraries --> <!-- and collections of general-purpose utility methods, Vue core --> <!-- is able to remain small by not reinventing them. This also --> <!-- gives you the freedom to just use what you're familiar with. --> <script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script> <script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script> <script> var watchExampleVM = new Vue({ el: '#watch-example', data: { question: '', answer: 'I cannot give you an answer until you ask a question!' }, watch: { // 如果 question 發(fā)生改變,這個(gè)函數(shù)就會(huì)運(yùn)行 question: function (newQuestion) { this.answer = 'Waiting for you to stop typing...' this.getAnswer() } }, methods: { // _.debounce 是一個(gè)通過 lodash 限制操作頻率的函數(shù)。 // 在這個(gè)例子中,我們希望限制訪問yesno.wtf/api的頻率 // ajax請(qǐng)求直到用戶輸入完畢才會(huì)發(fā)出 // 學(xué)習(xí)更多關(guān)于 _.debounce function (and its cousin // _.throttle), 參考: https://lodash.com/docs#debounce getAnswer: _.debounce( function () { var vm = this if (this.question.indexOf('?') === -1) { vm.answer = 'Questions usually contain a question mark. ;-)' return } vm.answer = 'Thinking...' axios.get('https://yesno.wtf/api') .then(function (response) { vm.answer = _.capitalize(response.data.answer) }) .catch(function (error) { vm.answer = 'Error! Could not reach the API. ' + error }) }, // 這是我們?yōu)橛脩敉V馆斎氲却暮撩霐?shù) 500 ) } }) </script> 在這個(gè)示例中,使用
watch選項(xiàng)允許我們執(zhí)行異步操作(訪問一個(gè) API),限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前,設(shè)置中間狀態(tài)。這是計(jì)算屬性無法做到的。除了 watch 選項(xiàng)之外,還有
vm.$watch命令。
Class 與 Style 綁定
綁定 HTML Class
對(duì)象語法
v-bind:class指令可以與普通的 class 屬性共存。-
可以直接綁定數(shù)據(jù)里的一個(gè)對(duì)象。
<div v-bind:class="classObject"></div>data: { classObject: { active: true, 'text-danger': false } } -
也可以在這里綁定返回對(duì)象的計(jì)算屬性。
<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 列表。-
如果需要根據(jù)條件切換列表中的 class ,可以用三元表達(dá)式。
<div v-bind:class="[isActive ? activeClass : '', errorClass]"> // 始終添加 errorClass ,但只有在 isActive 是 true 時(shí)添加 activeClass -
可以在數(shù)組語法中使用對(duì)象語法。
<div v-bind:class="[{ active: isActive }, errorClass]">
用在組件上
- 在一個(gè)定制的組件上用到
class屬性的時(shí)候,這些類將被添加到根元素上面,這個(gè)元素上已經(jīng)存在的類不會(huì)被覆蓋。
綁定內(nèi)聯(lián)樣式
- 和 Class 類似。
條件渲染
v-if
- 使用
v-if選擇性的渲染(不是顯示)元素。
v-else-if
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
- 類似于
v-else,v-else-if必須緊跟在v-if或者v-else-if元素之后。
用 key 管理可復(fù)用的元素
Vue 通常會(huì)復(fù)用已有元素而不是從頭開始渲染,以提升運(yùn)行效率。
-
例如:如果允許用戶在不同的登錄方式之間切換
<template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address"> </template>- 上面的代碼中切換
loginType將不會(huì)清除用戶已經(jīng)輸入的內(nèi)容。因?yàn)閮蓚€(gè)模版使用了相同的元素,<input>不會(huì)被替換掉——僅僅是替換了它的的placeholder。
- 上面的代碼中切換
-
有些情況下這樣做不符合需求。Vue 提供了一種方式來聲明兩個(gè)元素的獨(dú)立性:添加一個(gè)具有唯一值的
key屬性。<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>- 注意,
<label>元素仍然會(huì)被高效地復(fù)用,因?yàn)樗鼈儧]有添加key屬性。
- 注意,
v-show
- 使用
v-show根據(jù)條件展示元素。帶有v-show的元素始終會(huì)被渲染并保留在 DOM 中。v-show是簡(jiǎn)單地切換元素的 CSS 屬性display。 -
v-show不支持<template>語法,也不支持v-else。
v-if vs v-show
- 一般來說,
v-if有更高的切換開銷,而v-show有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用v-show較好;如果在運(yùn)行時(shí)條件不太可能改變,則使用v-if較好。
v-if 與 v-for 一起使用
- 當(dāng)
v-if與v-for一起使用時(shí),v-for具有比v-if更高的優(yōu)先級(jí)。
列表渲染
v-for
基本用法
-
在
v-for塊中,我們擁有對(duì)父作用域?qū)傩缘?strong>完全訪問權(quán)限。v-for還支持一個(gè)可選的第二個(gè)參數(shù)為當(dāng)前項(xiàng)的索引。<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作為分隔符。
Template v-for
-
可以用帶有
v-for的<template>標(biāo)簽來渲染多個(gè)元素塊。<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
對(duì)象迭代 v-for
-
可以用
v-for通過一個(gè)對(duì)象的屬性來迭代。<ul id="repeat-object" class="demo"> <li v-for="value in object"> {{ value }} </li> </ul>new Vue({ el: '#repeat-object', data: { object: { FirstName: 'John', LastName: 'Doe', Age: 30 } } }) -
也可以提供第二個(gè)的參數(shù)為鍵名,第三個(gè)參數(shù)作為索引。
<div v-for="(value, key) in object"> {{ key }} : {{ value }} </div><div v-for="(value, key, index) in object"> {{ index }}. {{ key }} : {{ value }} </div> 在遍歷對(duì)象時(shí),是按
Object.keys()的結(jié)果遍歷,但是不能保證它的結(jié)果在不同的 JavaScript 引擎下是一致的。
整數(shù)迭代 v-for
<div>
<span v-for="n in 10">{{ n }}</span>
</div>
組件 和 v-for
在自定義組件中,可以像普通元素一樣用
v-for。然而他不能自動(dòng)傳遞數(shù)據(jù)到組件里,因?yàn)榻M件有自己獨(dú)立的作用域。-
使用
props傳遞迭代數(shù)據(jù)到組件里。<my-component v-for="(item, index) in items" v-bind:item="item" v-bind:index="index"> </my-component> 不自動(dòng)注入
item到組件里的原因是,因?yàn)檫@使得組件會(huì)緊密耦合到v-for如何運(yùn)作。在一些情況下,明確數(shù)據(jù)的來源可以使組件可重用。
key
當(dāng) Vue.js 用
v-for正在更新已渲染過的元素列表時(shí),它默認(rèn)用 “就地復(fù)用“ 策略。如果數(shù)據(jù)項(xiàng)的順序被改變,Vue 將不是移動(dòng) DOM 元素來匹配數(shù)據(jù)項(xiàng)的順序, 而是簡(jiǎn)單復(fù)用此處每個(gè)元素,并且確保它在特定索引下顯示已被渲染過的每個(gè)元素。這個(gè)類似 Vue 1.x 的track-by="$index"。這個(gè)默認(rèn)的模式是有效的,但是只適用于不依賴子組件狀態(tài)或臨時(shí) DOM 狀態(tài)(例如:表單輸入值)的列表渲染輸出。
-
為了給 Vue 一個(gè)提示,以便它能跟蹤每個(gè)節(jié)點(diǎn)的身份,從而重用和重新排序現(xiàn)有元素,要為每項(xiàng)提供一個(gè)唯一
key屬性。理想的key值是每項(xiàng)都有唯一id。這個(gè)特殊的屬性相當(dāng)于 Vue 1.x 的track-by,但它的工作方式類似于一個(gè)屬性,所以要用v-bind來綁定動(dòng)態(tài)值。<div v-for="item in items" :key="item.id"> <!-- 內(nèi)容 --> </div> 建議盡可能使用
v-for來提供key,除非迭代 DOM 內(nèi)容足夠簡(jiǎn)單,或者你是故意要依賴于默認(rèn)行為來獲得性能提升。key并不特別與v-for關(guān)聯(lián),key還具有其他用途。
數(shù)組更新檢測(cè)
變異方法
- 修改當(dāng)前數(shù)組的方法,查閱 API。
重塑數(shù)組
- 使用一個(gè)新的數(shù)組代替原始數(shù)組。
- Vue 實(shí)現(xiàn)了一些智能啟發(fā)式方法來最大化 DOM 元素重用,所以用一個(gè)含有相同元素的數(shù)組去替換原來的數(shù)組是非常高效的操作。
注意事項(xiàng)
- 由于 JavaScript 的限制, Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:
- 當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如:
vm.items[indexOfItem] = newValue - 當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如:
vm.items.length = newLength
- 當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如:
顯示過濾 / 排序結(jié)果
-
通過創(chuàng)建返回過濾或排序數(shù)組的計(jì)算屬性來顯示一個(gè)數(shù)組的過濾或排序副本,而不實(shí)際改變或重置原始數(shù)據(jù)。
<li v-for="n in evenNumbers">{{ n }}</li>data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } } -
在計(jì)算屬性不適用的情況下 (例如,在嵌套 v-for 循環(huán)中) 使用 method 方法實(shí)現(xiàn)。
<li v-for="n in even(numbers)">{{ n }}</li>data: { numbers: [ 1, 2, 3, 4, 5 ] }, methods: { even: function (numbers) { return numbers.filter(function (number) { return number % 2 === 0 }) } }
事件處理器
內(nèi)聯(lián)處理器方法
-
有時(shí)也需要在內(nèi)聯(lián)語句處理器中訪問原生 DOM 事件。可以用特殊變量
$event把它傳入方法:(使用內(nèi)聯(lián)語句的時(shí)候因?yàn)榘远▍?shù),默認(rèn)不傳遞event)<button v-on:click="warn('Form cannot be submitted yet.', $event)">Submit</button>// ... methods: { warn: function (message, event) { // 現(xiàn)在我們可以訪問原生事件對(duì)象 if (event) event.preventDefault() alert(message) } }
事件修飾符
-
Vue.js 為
v-on提供了 事件修飾符。通過由點(diǎn)(.)表示的指令后綴來調(diào)用修飾符。<!-- 阻止單擊事件冒泡 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件不再重載頁面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修飾符可以串聯(lián) --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修飾符 --> <form v-on:submit.prevent></form> <!-- 添加事件偵聽器時(shí)使用事件捕獲模式 --> <div v-on:click.capture="doThis">...</div> <!-- 只當(dāng)事件在該元素本身(而不是子元素)觸發(fā)時(shí)觸發(fā)回調(diào) --> <div v-on:click.self="doThat">...</div> <!-- 2.14 新增:點(diǎn)擊事件將只會(huì)觸發(fā)一次 --> <a v-on:click.once="doThis"></a> .once修飾符還能被用到自定義的組件事件上。如果你還沒有閱讀關(guān)于組件的文檔,現(xiàn)在大可不必?fù)?dān)心。
按鍵修飾符
-
Vue 允許為
v-on在監(jiān)聽鍵盤事件時(shí)添加按鍵修飾符。<!-- 只有在 keyCode 是 13 時(shí)調(diào)用 vm.submit() --> <input v-on:keyup.13="submit"> -
記住所有的 keyCode 比較困難,所以 Vue 為最常用的按鍵提供了別名。
<!-- 同上 --> <input v-on:keyup.enter="submit"> <!-- 縮寫語法 --> <input @keyup.enter="submit"> -
可以通過全局
config.keyCodes對(duì)象自定義按鍵修飾符別名。// 可以使用 v-on:keyup.f1 Vue.config.keyCodes.f1 = 112 注意:在Mac系統(tǒng)鍵盤上,meta對(duì)應(yīng)命令鍵 (?)。在Windows系統(tǒng)鍵盤meta對(duì)應(yīng)windows徽標(biāo)鍵(?)。在Sun操作系統(tǒng)鍵盤上,meta對(duì)應(yīng)實(shí)心寶石鍵 (◆)。在其他特定鍵盤上,尤其在MIT和Lisp鍵盤及其后續(xù),比如Knight鍵盤,space-cadet鍵盤,meta被標(biāo)記為“META”。在Symbolics鍵盤上,meta被標(biāo)記為“META” 或者 “Meta”。
為什么在 HTML 中監(jiān)聽事件?
- 當(dāng)一個(gè) ViewModel 被銷毀時(shí),所有的事件處理器都會(huì)自動(dòng)被刪除。你無須擔(dān)心如何自己清理它們。
表單控件綁定
基礎(chǔ)用法
- 對(duì)于要求 IME (如中文、 日語、 韓語等) 的語言,你會(huì)發(fā)現(xiàn)
v-model不會(huì)在 ime 構(gòu)成中得到更新。如果你也想實(shí)現(xiàn)更新,請(qǐng)使用input事件。
綁定 value
- 對(duì)于單選按鈕,勾選框及選擇列表選項(xiàng),
v-model綁定的value通常是靜態(tài)字符串(對(duì)于勾選框是邏輯值)。 - 可以用
v-bind綁定 value 到 Vue 實(shí)例的一個(gè)動(dòng)態(tài)屬性上,這個(gè)屬性的值可以不是字符串。
復(fù)選框
<input
type="checkbox"
v-model="toggle"
v-bind:true-value="a"
v-bind:false-value="b"
>
// 當(dāng)選中時(shí)
vm.toggle === vm.a
// 當(dāng)沒有選中時(shí)
vm.toggle === vm.b
單選按鈕
<input type="radio" v-model="pick" v-bind:value="a">
// 當(dāng)選中時(shí)
vm.pick === vm.a
選擇列表設(shè)置
<select v-model="selected">
<!-- 內(nèi)聯(lián)對(duì)象字面量 -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
// 當(dāng)選中時(shí)
typeof vm.selected // -> 'object'
vm.selected.number // -> 123
修飾符
.lazy
-
在默認(rèn)情況下,
v-model在input事件中同步輸入框的值與數(shù)據(jù) (除了 上述 IME 部分),但你可以添加一個(gè)修飾符lazy,從而轉(zhuǎn)變?yōu)樵?change事件中同步。<!-- 在 "change" 而不是 "input" 事件中更新 --> <input v-model.lazy="msg" >
.number
- 如果想自動(dòng)將用戶的輸入值轉(zhuǎn)為 Number 類型(如果原值的轉(zhuǎn)換結(jié)果為 NaN 則返回原值),可以添加一個(gè)修飾符
number給v-model來處理輸入值。- 這通常很有用,因?yàn)樵?
type="number"時(shí) HTML 中輸入的值也總是會(huì)返回字符串類型。
- 這通常很有用,因?yàn)樵?
.trim
-
如果要自動(dòng)過濾用戶輸入的首尾空格,可以添加
trim修飾符到v-model上過濾輸入。<input v-model.trim="msg">
v-model 與組件
- Vue 的組件系統(tǒng)允許你創(chuàng)建一個(gè)具有自定義行為可復(fù)用的
input類型,這些input類型甚至可以和v-model一起使用!要了解更多,請(qǐng)參閱自定義input類型
組件
使用組件
DOM 模板解析說明
當(dāng)使用 DOM 作為模版時(shí)(例如,將
el選項(xiàng)掛載到一個(gè)已存在的元素上), 你會(huì)受到 HTML 的一些限制,因?yàn)?Vue 只有在瀏覽器解析和標(biāo)準(zhǔn)化 HTML 后才能獲取模版內(nèi)容。尤其像這些元素<ul>,<ol>,<table>,<select>限制了能被它包裹的元素,<option>只能出現(xiàn)在其它元素內(nèi)部。-
在自定義組件中使用這些受限制的元素時(shí)會(huì)導(dǎo)致一些問題,例如:
<table> <my-row>...</my-row> </table>自定義組件
<my-row>被認(rèn)為是無效的內(nèi)容,因此在渲染的時(shí)候會(huì)導(dǎo)致錯(cuò)誤。變通的方案是使用特殊的is屬性:<table> <tr is="my-row"></tr> </table> -
應(yīng)當(dāng)注意,如果您使用來自以下來源之一的字符串模板,這些限制將不適用:
<script type="text/x-template">- JavaScript內(nèi)聯(lián)模版字符串
-
.vue組件
data 必須是函數(shù)
- 通過 Vue 構(gòu)造器傳入的各種選項(xiàng)大多數(shù)都可以在組件里用。
data是一個(gè)例外,它必須是函數(shù)。
構(gòu)成組件
- 在 Vue.js 中,父子組件的關(guān)系可以總結(jié)為 props down, events up 。父組件通過
props向下傳遞數(shù)據(jù)給子組件,子組件通過events給父組件發(fā)送消息。
父子組件通信流程
Prop
camelCase vs kebab-case
- 使用字符串模板時(shí),不需要將 camelCase 轉(zhuǎn)換成 kebab-case 。
字面量語法 vs 動(dòng)態(tài)語法
-
使用字面量語法傳遞數(shù)值會(huì)得到字符串。
<!-- 傳遞了一個(gè)字符串"1" --> <comp some-prop="1"></comp> -
如果想傳遞一個(gè)實(shí)際的
number,需要使用v-bind,從而讓它的值被當(dāng)作 JavaScript 表達(dá)式計(jì)算。<!-- 傳遞實(shí)際的mumber --> <comp v-bind:some-prop="1"></comp>
單向數(shù)據(jù)流
不應(yīng)該在子組件內(nèi)部改變
prop,Vue 會(huì)在控制臺(tái)給出警告。-
prop 作為初始值傳入后,子組件想把它當(dāng)作局部數(shù)據(jù)來用:定義一個(gè)局部變量,并用 prop 的值初始化它。
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } } -
prop 作為初始值傳入,由子組件處理成其它數(shù)據(jù)輸出:定義一個(gè)計(jì)算屬性,處理 prop 的值并返回。
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } } 在 JavaScript 中對(duì)象和數(shù)組是引用類型,指向同一個(gè)內(nèi)存空間,如果
prop是一個(gè)對(duì)象或數(shù)組,在子組件內(nèi)部改變它會(huì)影響父組件的狀態(tài)。
Prop 驗(yàn)證
-
我們可以為組件的
props指定驗(yàn)證規(guī)格。如果傳入的數(shù)據(jù)不符合規(guī)格,Vue 會(huì)發(fā)出警告。要指定驗(yàn)證規(guī)格,需要用對(duì)象的形式,而不能用字符串?dāng)?shù)組。Vue.component('example', { props: { // 基礎(chǔ)類型檢測(cè) (`null` 意思是任何類型都可以) propA: Number, // 多種類型 propB: [String, Number], // 必傳且是字符串 propC: { type: String, required: true }, // 數(shù)字,有默認(rèn)值 propD: { type: Number, default: 100 }, // 數(shù)組/對(duì)象的默認(rèn)值應(yīng)當(dāng)由一個(gè)工廠函數(shù)返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定義驗(yàn)證函數(shù) propF: { validator: function (value) { return value > 10 } } } }) type可以是StringNumberBooleanFunctionObjectArray,type也可以是一個(gè)自定義構(gòu)造器函數(shù),使用instanceof檢測(cè)。當(dāng) prop 驗(yàn)證失敗,Vue會(huì)在拋出警告 (如果使用的是開發(fā)版本)。
自定義事件
子組件通過自定義事件向父組件回傳數(shù)據(jù)。
-
每個(gè) Vue 實(shí)例都實(shí)現(xiàn)了事件接口:
- 使用
$on(eventName)監(jiān)聽事件。 - 使用
$emit(eventName)觸發(fā)事件。
- 使用
Vue 的事件系統(tǒng)分離自瀏覽器的 EventTarget API 。盡管它們的運(yùn)行類似,但是
$on和$emit不是addEventListener和dispatchEvent的別名。-
父組件可以在使用子組件的地方直接用
v-on來監(jiān)聽子組件觸發(fā)的事件。-
不能用
$on偵聽子組件拋出的事件,而必須在模板里直接用v-on綁定。
<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div>Vue.component('button-counter', { template: '<button v-on:click="increment">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { increment: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } })子組件已經(jīng)和它外部完全解耦了。它所做的只是報(bào)告自己的內(nèi)部事件,至于父組件是否關(guān)心則與它無關(guān)。留意到這一點(diǎn)很重要。
-
不能用
-
在某個(gè)組件的根元素上監(jiān)聽一個(gè)原生事件??梢允褂?
.native修飾v-on。<my-component v-on:click.native="doTheThing"></my-component>
使用自定義事件處理表單輸入組件
-
自定義事件可以用來創(chuàng)建自定義的表單輸入組件,使用
v-model來進(jìn)行數(shù)據(jù)雙向綁定。<input v-model="something">等價(jià)于:
<input v-bind:value="something" v-on:input="something = $event.target.value">在組件中使用時(shí),它相當(dāng)于下面的簡(jiǎn)寫:
<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input> -
要讓組件的
v-model生效,它必須:- 接受一個(gè)
value屬性。 - 在有新的
value時(shí)觸發(fā) input 事件。
- 接受一個(gè)
非父子組件通信
-
在簡(jiǎn)單的場(chǎng)景下,可以使用一個(gè)空的 Vue 實(shí)例作為中央事件總線。
var bus = new Vue() s = new Vue()// 觸發(fā)組件 A 中的事件 bus.$emit('id-selected', 1)// 在組件 B 創(chuàng)建的鉤子中監(jiān)聽事件 bus.$on('id-selected', function (id) { // ... }) 在復(fù)雜的情況下,考慮使用專門的狀態(tài)管理模式。
使用 slot 分發(fā)內(nèi)容
作用域插槽
作用域插槽是一種特殊類型的插槽,用作使用一個(gè)(能夠傳遞數(shù)據(jù)到)可重用模板替換已渲染元素。
-
在子組件中,只需將數(shù)據(jù)傳遞到插槽,就像你將
prop傳遞給組件一樣:<div class="child"> <slot text="hello from child"></slot> </div> -
在父級(jí)中,具有特殊屬性
scope的<template>元素,表示它是作用域插槽的模板。scope的值對(duì)應(yīng)一個(gè)臨時(shí)變量名,此變量接收從子組件中傳遞的prop對(duì)象:<div class="parent"> <child> <template scope="props"> <span>hello from parent</span> <span>{{ props.text }}</span> </template> </child> </div> -
渲染結(jié)果:
<div class="parent"> <div class="child"> <span>hello from parent</span> <span>hello from child</span> </div> </div> -
作用域插槽更具代表性的用例是列表組件,允許組件自定義應(yīng)該如何渲染列表每一項(xiàng):
<my-awesome-list :items="items"> <!-- 作用域插槽也可以在這里命名 --> <template slot="item" scope="props"> <li class="my-fancy-item">{{ props.text }}</li> </template> </my-awesome-list>列表組件模板:
<ul> <slot name="item" v-for="item in items" :text="item.text"> <!-- fallback content here --> </slot> </ul>
動(dòng)態(tài)組件
-
通過使用保留的
<component>元素,動(dòng)態(tài)地綁定到它的is特性,我們讓多個(gè)組件可以使用同一個(gè)掛載點(diǎn),并動(dòng)態(tài)切換:var vm = new Vue({ el: '#example', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })<component v-bind:is="currentView"> <!-- 組件在 vm.currentview 變化時(shí)改變! --> </component>也可以直接綁定到組件對(duì)象上:
var Home = { template: '<p>Welcome home!</p>' } var vm = new Vue({ el: '#example', data: { currentView: Home } })
keep-alive
-
如果把切換出去的組件保留在內(nèi)存中,可以保留它的狀態(tài)或避免重新渲染。為此可以添加一個(gè)
keep-alive指令參數(shù):<keep-alive> <component :is="currentView"> <!-- 非活動(dòng)組件將被緩存! --> </component> </keep-alive>- 詳見 API 參考。
雜項(xiàng)
子組件索引
-
可以使用
ref為子組件指定一個(gè)索引 ID 以在 JavaScript 中直接訪問子組件。<div id="parent"> <user-profile ref="profile"></user-profile> </div>var parent = new Vue({ el: '#parent' }) // 訪問子組件 var child = parent.$refs.profile 當(dāng) ref 和 v-for 一起使用時(shí), ref 是一個(gè)數(shù)組或?qū)ο螅鄳?yīng)的子組件。
$refs只在組件渲染完成后才填充,并且它是非響應(yīng)式的。它僅僅作為一個(gè)直接訪問子組件的應(yīng)急方案——應(yīng)當(dāng)避免在模版或計(jì)算屬性中使用$refs。
異步組件
Vue.js 允許將組件定義為一個(gè)工廠函數(shù),動(dòng)態(tài)地解析組件的定義。Vue.js 只在組件需要渲染時(shí)觸發(fā)工廠函數(shù),并且把結(jié)果緩存起來,用于后面的再次渲染。
-
一個(gè)例子
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { resolve({ template: '<div>I am async!</div>' }) }, 1000) })工廠函數(shù)接收一個(gè)
resolve回調(diào),在收到從服務(wù)器下載的組件定義時(shí)調(diào)用。也可以調(diào)用reject(reason)指示加載失敗。這里setTimeout只是為了演示。怎么獲取組件完全由你決定。推薦配合使用 Webpack 的代碼分割功能Vue.component('async-webpack-example', function (resolve) { // 這個(gè)特殊的 require 語法告訴 webpack // 自動(dòng)將編譯后的代碼分割成不同的塊, // 這些塊將通過 ajax 請(qǐng)求自動(dòng)下載。 require(['./my-async-component'], resolve) })
遞歸組件
-
有
name選項(xiàng)的組件可以在模板內(nèi)部遞歸調(diào)用自己。var StackOverflow = Vue.extend({ name: 'stack-overflow', template: '<div>' + // 遞歸地調(diào)用它自己 '<stack-overflow></stack-overflow>' + '</div>' })上面組件會(huì)導(dǎo)致一個(gè)錯(cuò)誤 “max stack size exceeded”,所以要確保遞歸調(diào)用有終止條件。
組件間的循環(huán)引用(Circular References Between Components)
內(nèi)聯(lián)模板
-
如果子組件有
inline-template特性,組件將把它的內(nèi)容當(dāng)做它的模板,而不是分發(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é)果。最佳實(shí)踐是使用template選項(xiàng)在組件內(nèi)定義模板或者在.vue文件中使用template元素。
X-Templates
-
另一種定義模版的方式是在 JavaScript 標(biāo)簽里使用 text/x-template 類型,并且指定一個(gè)id。
<script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script>Vue.component('hello-world', { template: '#hello-world-template' }) 這在有很多模版或者小的應(yīng)用中有用,否則應(yīng)該避免使用,因?yàn)樗鼘⒛0婧徒M件的其他定義隔離了。
對(duì)低開銷的靜態(tài)組件使用 v-once
-
盡管在 Vue 中渲染 HTML 很快,不過當(dāng)組件中包含大量靜態(tài)內(nèi)容時(shí),可以考慮使用 v-once 將渲染結(jié)果緩存起來。
Vue.component('terms-of-service', { template: '\ <div v-once>\ <h1>Terms of Service</h1>\ ... a lot of static content ...\ </div>\ ' })
深入響應(yīng)式原理
- Vue 使用
Object.defineProperty把 Vue 實(shí)例的data中的屬性全部轉(zhuǎn)換為 getter / setter 。 - 在內(nèi)部,Vue 會(huì)追蹤依賴,在屬性被訪問和修改時(shí)通知變化。
- 每個(gè)組件實(shí)例都有相應(yīng)的
watcher實(shí)例對(duì)象,它會(huì)在組件渲染的過程中把屬性記錄為依賴,之后當(dāng)依賴項(xiàng)的setter被調(diào)用時(shí),會(huì)通知watcher重新計(jì)算,從而致使它關(guān)聯(lián)的組件得以更新。
變化檢測(cè)問題
由于 Vue 會(huì)在初始化實(shí)例時(shí)對(duì)屬性執(zhí)行
getter/setter轉(zhuǎn)化過程,所以屬性必須在data對(duì)象上存在才能讓 Vue 轉(zhuǎn)換它,這樣才能讓它是響應(yīng)的。-
Vue 不允許在已經(jīng)創(chuàng)建的實(shí)例上動(dòng)態(tài)添加新的根級(jí)響應(yīng)式屬性(root-level reactive property)。然而它可以使用
Vue.set(object, key, value)方法將響應(yīng)屬性添加到嵌套的對(duì)象上,也可以使用vm.$set實(shí)例方法,這也是全局Vue.set方法的別名。Vue.set(vm.someObject, 'b', 2) this.$set(this.someObject,'b',2) 使用
Object.assign()或_.extend()等方法添加到對(duì)象上的新屬性不會(huì)觸發(fā)更新。-
可以創(chuàng)建一個(gè)新的對(duì)象,讓它包含原對(duì)象的屬性和新的屬性:
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })` this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
聲明響應(yīng)式屬性
- 必須在初始化實(shí)例前聲明根級(jí)響應(yīng)式屬性,哪怕只是一個(gè)空值。
異步更新隊(duì)列
Vue 異步執(zhí)行 DOM 更新。
-
為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM ,可以在數(shù)據(jù)變化之后立即使用
Vue.nextTick(callback)。這樣回調(diào)函數(shù)在 DOM 更新完成后就會(huì)調(diào)用。<div id="example">{{message}}</div>var vm = new Vue({ el: '#example', data: { message: '123' } }) vm.message = 'new message' // 更改數(shù)據(jù) vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true }) -
在組件內(nèi)使用
vm.$nextTick()實(shí)例方法特別方便,因?yàn)樗恍枰?Vue ,并且回調(diào)函數(shù)中的this將自動(dòng)綁定到當(dāng)前的 Vue 實(shí)例上。Vue.component('example', { template: '<span>{{ message }}</span>', data: function () { return { message: 'not updated' } }, methods: { updateMessage: function () { this.message = 'updated' console.log(this.$el.textContent) // => '沒有更新' this.$nextTick(function () { console.log(this.$el.textContent) // => '更新完成' }) } } })
過渡效果
概述
- Vue 允許多種過渡動(dòng)畫:
- 在 CSS 過渡和動(dòng)畫中自動(dòng)應(yīng)用 class
- 配合使用第三方 CSS 動(dòng)畫庫
- 在過渡鉤子函數(shù)中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 動(dòng)畫庫,如 Velocity.js
單元素 / 組件的過渡
- Vue 提供了
transition的封裝組件。在下列情形中,可以為元素或組件添加 entering / leaving 效果:- v-if
- v-show
- 動(dòng)態(tài)組件
- 組件根節(jié)點(diǎn)
- 當(dāng)插入或刪除包含在
transition組件中的元素時(shí),Vue 會(huì)進(jìn)行以下處理:- 自動(dòng)嗅探目標(biāo)元素是否應(yīng)用了 CSS 過渡或動(dòng)畫,如果是,在恰當(dāng)?shù)臅r(shí)機(jī)添加 / 刪除 CSS 類名。
- 如果過渡組件提供了 JavaScript 鉤子函數(shù),這些鉤子函數(shù)會(huì)在恰當(dāng)時(shí)機(jī)被調(diào)用。
- 如果沒有找到鉤子函數(shù)也沒有檢測(cè)到 CSS 過渡 / 動(dòng)畫,DOM 操作在下一幀中立即執(zhí)行。
過渡的 CSS 類型
-
Vue 包含 4 個(gè)( CSS ) 類名在 enter / leave 的過渡中切換。
-
v-enter:定義進(jìn)入過渡的開始狀態(tài)。在元素被插入時(shí)生效,在下一個(gè)幀移除。 -
v-enter-active:定義進(jìn)入過渡的結(jié)束狀態(tài)。在元素被插入時(shí)生效,在transition/animation完成之后移除。 -
v-leave:定義離開過渡的開始狀態(tài)。在離開過渡被觸發(fā)時(shí)生效,在下一個(gè)幀移除。 -
v-leave-active:定義離開過渡的結(jié)束狀態(tài)。在離開過渡被觸發(fā)時(shí)生效,在transition/animation完成之后移除。
-
使用
<transition name="my-transition">可以重置類名的v-前綴。
CSS 動(dòng)畫 與 CSS 過渡
- 在 CSS animation 中,
v-enter類名在節(jié)點(diǎn)插入 DOM 后不會(huì)立即刪除。而是在animationend事件觸發(fā)時(shí)刪除。
自定義過渡類名
-
<transition>允許通過以下屬性自定義過渡類名:enter-classenter-active-classleave-classleave-active-class
同時(shí)使用 Transitions 和 Animations
Vue 為了知道過渡的完成,必須設(shè)置相應(yīng)的事件監(jiān)聽器。它可以是 transitionend 或 animationend ,這取決于給元素應(yīng)用的 CSS 規(guī)則。如果你使用其中任何一種,Vue 能自動(dòng)識(shí)別類型并設(shè)置監(jiān)聽。
但是,在一些場(chǎng)景中,你需要給同一個(gè)元素同時(shí)設(shè)置兩種過渡動(dòng)效,比如 animation 很快的被觸發(fā)并完成了,而 transition 效果還沒結(jié)束。在這種情況中,你就需要使用 type 特性并設(shè)置 animation 或 transition 來明確聲明你需要 Vue 監(jiān)聽的類型。
JavaScript 鉤子
- 可以在
<transition>的屬性中聲明 JavaScript 鉤子:-
@before-enter:function (el) -
@enter:function(el, done) -
@after-enter:function (el) -
@enter-cancelled:function (el) -
@before-leave:function (el) -
@leave:function(el, done) -
@after-leave:function (el) -
@leave-cancelled:function (el)
-
- 鉤子函數(shù)可以結(jié)合 CSS 過渡動(dòng)畫一起使用,也可以單獨(dú)使用,但是:
- 當(dāng)只使用 JavaScript 過渡的時(shí)候,在
enter和leave中,回調(diào)函數(shù)done是必須的。否則它們會(huì)被同步調(diào)用,過渡會(huì)立即完成。 - 推薦對(duì)于僅使用 JavaScript 過渡的
<transition>添加:css="false",Vue 會(huì)跳過 CSS 檢測(cè)。
- 當(dāng)只使用 JavaScript 過渡的時(shí)候,在
初始渲染的過渡
可以通過 appear 特性設(shè)置節(jié)點(diǎn)在初始化渲染時(shí)的過渡。
<transition appear>
...
</transition>
-
這里的
<transition>同樣允許自定義 CSS 類名或 JavaScript 鉤子:<transition appear appear-class="custom-appear-class" appear-active-class="custom-appear-active-class" > <!-- ... --> </transition> <transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" > <!-- ... --> </transition>
多個(gè)元素的過渡
對(duì)于原生標(biāo)簽,可以使用
v-if / v-else在控制多個(gè)元素的過渡。當(dāng)有相同標(biāo)簽名的元素切換時(shí),要通過
key特性設(shè)置唯一的值來標(biāo)記以讓 Vue 區(qū)分它們。即使在技術(shù)上沒有必要,給在<transition>組件中的多個(gè)元素設(shè)置 key 是一個(gè)更好的實(shí)踐。-
使用多個(gè)
v-if的多個(gè)元素的過渡可以重寫為綁定了動(dòng)態(tài)屬性的單個(gè)過渡元素。<transition> <button v-if="docState === 'saved'" key="saved"> Edit </button> <button v-if="docState === 'edited'" key="edited"> Save </button> <button v-if="docState === 'editing'" key="editing"> Cancel </button> </transition>重寫為
<transition> <button v-bind:key="docState"> {{ buttonMessage }} </button> </transition>// ... computed: { buttonMessage: function () { switch (docState) { case 'saved': return 'Edit' case 'edited': return 'Save' case 'editing': return 'Cancel' } } }
過渡模式
-
<transition>在使用v-if的多組件上作用過渡時(shí),進(jìn)入和離開會(huì)同時(shí)發(fā)生,這有可能導(dǎo)致布局錯(cuò)亂或樣式重疊。可以在過渡的時(shí)候?qū)υ厥褂媒^對(duì)定位。(可以實(shí)現(xiàn) button 滑動(dòng)切換的效果) - 為了解決上述問題,Vue 提供了過渡模式:
-
in-out新元素先進(jìn)行過渡,完成之后當(dāng)前元素過渡離開。 -
out-in當(dāng)前元素先進(jìn)行過渡,完成之后新元素過渡離開。
-
多個(gè)組件的過渡
-
組件過渡不需要使用
key特性,只需要使用<component>構(gòu)建的動(dòng)態(tài)組件即可。<transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition>
列表過渡
- 使用
<transition-group>渲染列表。 - 不同于
<transition>,<transition-group>會(huì)以一個(gè)真實(shí)的元素呈現(xiàn)。默認(rèn)為一個(gè)<span>,也可以通過tag屬性更換。 - 內(nèi)部元素總是需要提供一個(gè)唯一的
key值。
列表的進(jìn)入和離開過渡
-
<transition-group>同樣支持自定義前綴或自定義類名,與<transition>完全相同。
列表的位移過渡
<transition-group>組件可以改變定位。使用其v-move特性,它會(huì)在元素改變定位的過程中應(yīng)用??梢允褂?name改變前綴,也可以使用move-class手動(dòng)指定類名。-
Vue 使用了一個(gè)叫 FLIP 的簡(jiǎn)單的動(dòng)畫隊(duì)列,使用
transforms將元素從之前的位置平滑過渡新的位置。.list-item { display: inline-block; margin-right: 10px; } .list-enter-active, .list-leave-active { transition: all 1s; } .list-enter, .list-leave-active { opacity: 0; transform: translateY(30px); } FLIP 同樣支持多維網(wǎng)格過渡。
列表的漸進(jìn)過渡
- 通過 data 屬性與 JavaScript 通信,可以實(shí)現(xiàn)列表的漸進(jìn)過渡。技巧是設(shè)置 delay 。(可以參考官方文檔的示例)
可復(fù)用的過渡
- 把
<transition>封裝成一個(gè)組件,即可進(jìn)行復(fù)用。
動(dòng)態(tài)過渡
- 動(dòng)態(tài)過渡最基本的例子是通過
name特性來綁定動(dòng)態(tài)值。 - 利用過渡事件,根據(jù)組件的狀態(tài)通過 JavaScript 過渡設(shè)置不同的過渡效果。
- 創(chuàng)建動(dòng)態(tài)過渡的最終方案是組件通過接受
props來動(dòng)態(tài)修改之前的過渡。
過渡狀態(tài)
- 對(duì)于數(shù)據(jù)元素本身的動(dòng)態(tài)效果,Vue 允許結(jié)合第三方庫實(shí)現(xiàn)切換動(dòng)畫。
狀態(tài)動(dòng)畫與 watcher
- 通過 watcher 我們能監(jiān)聽到任何屬性的數(shù)值更新,并可以獲取到更新前和更新后的兩組數(shù)值。這樣,就可以利用第三方庫,結(jié)合舊數(shù)據(jù)和新數(shù)據(jù)構(gòu)建過渡動(dòng)畫了。
動(dòng)態(tài)狀態(tài)轉(zhuǎn)換
通過組件組織過渡
- 將一些通用的動(dòng)畫效果提取到專用的子組件里。
Render 函數(shù)
-
一個(gè)例子
Vue.component('anchored-heading', { render: function (createElement) { return createElement( 'h' + this.level, // tag name 標(biāo)簽名稱 this.$slots.default // 子組件中的陣列 ) }, props: { level: { type: Number, required: true } } }) 需要知道當(dāng)你不使用
slot屬性向組件中傳遞內(nèi)容時(shí), 這些子元素被存儲(chǔ)在組件實(shí)例中的 $slots.default中。詳見 instance properties API
createElement 參數(shù)
-
createElement接受的參數(shù):// @returns {VNode} createElement( // {String | Object | Function} // 一個(gè) HTML 標(biāo)簽字符串,組件選項(xiàng)對(duì)象,或者一個(gè)返回值類型為String/Object的函數(shù),必要參數(shù) 'div', // {Object} // 一個(gè)包含模板相關(guān)屬性的數(shù)據(jù)對(duì)象 // 這樣,您可以在 template 中使用這些屬性.可選參數(shù). { // (詳情見下一節(jié)) }, // {String | Array} // 子節(jié)點(diǎn)(VNodes),可以是一個(gè)字符串或者一個(gè)數(shù)組. 可選參數(shù). [ createElement('h1', 'hello world'), createElement(MyComponent, { props: { someProp: 'foo' } }), 'bar' ] )createElement的第二個(gè)參數(shù)是可選參數(shù),且必須接收一個(gè)Object。
深入 data object 對(duì)象
-
在 VNode 數(shù)據(jù)對(duì)象中,下列屬性名是級(jí)別最高的字段。
{ // 和`v-bind:class`一樣的 API 'class': { foo: true, bar: false }, // 和`v-bind:style`一樣的 API style: { color: 'red', fontSize: '14px' }, // 正常的 HTML 特性 attrs: { id: 'foo' }, // 組件 props props: { myProp: 'bar' }, // DOM 屬性 domProps: { innerHTML: 'baz' }, // 事件監(jiān)聽器基于 "on" // 所以不再支持如 v-on:keyup.enter 修飾器 // 需要手動(dòng)匹配 keyCode。 on: { click: this.clickHandler }, // 僅對(duì)于組件,用于監(jiān)聽原生事件,而不是組件內(nèi)部使用 vm.$emit 觸發(fā)的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定義指令. 注意事項(xiàng):不能對(duì)綁定的舊值設(shè)值 // Vue 會(huì)為您持續(xù)追蹤 directives: [ { name: 'my-custom-directive', value: '2' expression: '1 + 1', arg: 'foo', modifiers: { bar: true } } ], // Scoped slots in the form of // { name: props => VNode | Array<VNode> } scopedSlots: { default: props => h('span', props.text) }, // 如果組件是其他組件的子組件,需為slot指定名稱 slot: 'name-of-slot' // 其他特殊頂層屬性 key: 'myKey', ref: 'myRef' }
約束
-
VNode 必須唯一:組件樹中的所有 VNodes 必須是唯一的。下面的 render function 無效:
render: function (createElement) { var myParagraphVNode = createElement('p', 'hi') return createElement('div', [ // 錯(cuò)誤-重復(fù)的VNodes myParagraphVNode, myParagraphVNode ]) } -
使用工廠函數(shù)來實(shí)現(xiàn)重復(fù):
render: function (createElement) { return createElement('div', Array.apply(null, { length: 20 }).map(function () { return createElement('p', 'hi') }) ) }
使用 JavaScript 代替模板功能
v-if and v-for
-
在 render 函數(shù)中使用 JavaScript 的 if/else 和 map 重寫
v-if和v-for:render: function (createElement) { if (this.items.length) { return createElement('ul', this.items.map(function (item) { return createElement('li', item.name) })) } else { return createElement('p', 'No items found.') } }
v-model
-
render函數(shù)中沒有與v-model相應(yīng)的 API - 你必須自己來實(shí)現(xiàn)相應(yīng)的邏輯render: function (createElement) { var self = this return createElement('input', { domProps: { value: self.value }, on: { input: function (event) { self.value = event.target.value } } }) }
事件 & 按鍵修飾符
-
一個(gè)例子:
on: { '!click': this.doThisInCapturingMode, '~keyup': this.doThisOnce, `~!mouseover`: this.doThisOnceInCapturingMode }
slots
-
可以從
this.$slots獲取 VNodes 列表中的靜態(tài)內(nèi)容:render: function (createElement) { // <div><slot></slot></div> return createElement('div', this.$slots.default) } -
然后從
this.$scopedSlots中以返回 VNodes 的函數(shù)返回值的形式訪問局部 slots 。render: function (createElement) { // <div><slot :text="msg"></slot></div> return createElement('div', [ this.$scopedSlots.default({ text: this.msg }) ]) } -
在 render function 中,使用 VNode data 中的
scopedSlots域向子組件傳遞傳遞局部 slots 。render (createElement) { return createElement('div', [ createElement('child', { // pass scopedSlots in the data object // in the form of { name: props => VNode | Array<VNode> } scopedSlots: { default: function (props) { return createElement('span', props.text) } } }) ]) }
JSX
-
Babel plugin 插件,用于在 Vue 中使用 JSX 語法。
import AnchoredHeading from './AnchoredHeading.vue' new Vue({ el: '#demo', render (h) { return ( <AnchoredHeading level={1}> <span>Hello</span> world! </AnchoredHeading> ) } })將
h作為createElement的別名是 Vue 生態(tài)系統(tǒng)中的一個(gè)通用慣例,實(shí)際上也是 JSX 所要求的,如果在作用域中h失去作用, 在應(yīng)用中會(huì)觸發(fā)報(bào)錯(cuò)。
函數(shù)化組件
-
一個(gè)例子
Vue.component('my-component', { functional: true, // 為了彌補(bǔ)缺少的實(shí)例 // 提供第二個(gè)參數(shù)作為上下文 render: function (createElement, context) { // ... }, // Props 可選 props: { // ... } })
slots() 和 children 對(duì)比
-
對(duì)于下面這個(gè)組件:
<my-functional-component> <p slot="foo"> first </p> <p>second</p> </my-functional-component>-
children會(huì)給你兩個(gè)段落標(biāo)簽,而slots().default只會(huì)傳遞第二個(gè)匿名段落標(biāo)簽,slots().foo會(huì)傳遞第一個(gè)具名段落標(biāo)簽。
-
可以選擇讓組件通過
slot()系統(tǒng)分發(fā)或者簡(jiǎn)單的通過 children 接收,讓其他組件去處理。
自定義指令
基礎(chǔ)
-
Vue.js 允許用戶通過
Vue.directive(id, definition)方法注冊(cè)一個(gè)全局自定義指令,接收兩個(gè)參數(shù):指令 ID 和 定義對(duì)象。也可以用組件的directive選項(xiàng)注冊(cè)一個(gè)局部自定義指令。// 注冊(cè)一個(gè)全局自定義指令 v-focus Vue.directive('focus', { // 當(dāng)綁定元素插入到 DOM 中。 inserted: function (el) { // 聚焦元素 el.focus() } })directives: { focus: { // 指令的定義--- } }使用:
<input v-focus>
鉤子函數(shù)
- 指令定義函數(shù)提供了幾個(gè)鉤子函數(shù)(可選):
-
bind: 只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用,用這個(gè)鉤子函數(shù)可以定義一個(gè)在綁定時(shí)執(zhí)行一次的初始化動(dòng)作。 -
inserted: 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用,不必存在于 document 中)。 -
update: 被綁定元素所在的模板更新時(shí)調(diào)用,而不論綁定值是否變化。通過比較更新前后的綁定值,可以忽略不必要的模板更新(詳細(xì)的鉤子函數(shù)參數(shù)見下)。 -
componentUpdated: 被綁定元素所在模板完成一次更新周期時(shí)調(diào)用。 -
unbind: 只調(diào)用一次, 指令與元素解綁時(shí)調(diào)用。
-
鉤子函數(shù)參數(shù)
- 鉤子函數(shù)被賦予了以下參數(shù):
el: 指令所綁定的元素,可以用來直接操作 DOM 。-
binding: 一個(gè)對(duì)象,包含以下屬性:-
name: 指令名,不包括v-前綴。 -
value: 指令的綁定值, 例如:v-my-directive="1 + 1",value的值是2。 -
oldValue: 指令綁定的前一個(gè)值,僅在update和componentUpdated鉤子中可用。無論值是否改變都可用。 -
expression: 綁定值的字符串形式。 例如v-my-directive="1 + 1",expression的值是"1 + 1"。 -
arg: 傳給指令的參數(shù)。例如v-my-directive:foo,arg的值是"foo"。 -
modifiers: 一個(gè)包含修飾符的對(duì)象。 例如:v-my-directive.foo.bar,修飾符對(duì)象modifiers的值是{ foo: true, bar: true }。
-
vnode: Vue 編譯生成的虛擬節(jié)點(diǎn),查閱 VNode API 了解更多詳情。oldVnode: 上一個(gè)虛擬節(jié)點(diǎn),僅在update和componentUpdated鉤子中可用。除了
el之外,其它參數(shù)都應(yīng)該是只讀的,盡量不要修改他們。如果需要在鉤子之間共享數(shù)據(jù),建議通過元素的 dataset 來進(jìn)行。-
一個(gè)例子:
<div id="hook-arguments-example" v-demo:hello.a.b="message"></div>Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } })
函數(shù)簡(jiǎn)寫
-
大多數(shù)情況下,我們可能想在
bind和update鉤子上做重復(fù)動(dòng)作,并且不想關(guān)心其它的鉤子函數(shù)??梢赃@樣寫:Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value })
對(duì)象字面量
-
如果指令需要多個(gè)值,可以傳入一個(gè) JavaScript 對(duì)象字面量。指令函數(shù)能夠接受所有合法類型的 JavaScript 表達(dá)式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // => "white" console.log(binding.value.text) // => "hello!" })
混合
基礎(chǔ)
-
混合以一種靈活的方式為組件提供分布復(fù)用功能?;旌蠈?duì)象可以包含任意的組件選項(xiàng)。當(dāng)組件使用了混合對(duì)象時(shí),混合對(duì)象的所有選項(xiàng)將被“混入”組件自己的選項(xiàng)中。
// 定義一個(gè)混合對(duì)象 var myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } } // 定義一個(gè)組件,使用這個(gè)混合對(duì)象 var Component = Vue.extend({ mixins: [myMixin] }) var component = new Component() // -> "hello from mixin!"
選項(xiàng)合并
- 當(dāng)混合對(duì)象與組件包含同名選項(xiàng)時(shí),這些選項(xiàng)將以適當(dāng)?shù)牟呗?/strong>合并。
- 混合的鉤子將在組件自己的鉤子之前調(diào)用。
- 注意
Vue.extend()使用同樣的合并策略。 - 可以參考這里
全局混合
-
一旦使用全局混合對(duì)象,將會(huì)影響到所有之后創(chuàng)建的 Vue 實(shí)例。使用恰當(dāng)時(shí),可以為自定義對(duì)象注入處理邏輯。但是通常不建議使用。語法如下:
// 為自定義的選項(xiàng) 'myOption' 注入一個(gè)處理器。 Vue.mixin({ created: function () { var myOption = this.$options.myOption if (myOption) { console.log(myOption) } } }) new Vue({ myOption: 'hello!' }) // -> "hello!"
自定義選項(xiàng)混合策略
單文件組件
- 可以使用 vue-cli 或者參考我的另一篇文章:用 Vue + vue-router + Webpack 構(gòu)建單頁 Web APP (SPA)
- 官方文檔:單文件組件
生產(chǎn)環(huán)境部署
單元測(cè)試
[整理中][官方文檔]
服務(wù)端渲染
[整理中][官方文檔]


