一、選項 / 資料
1.data
當一個元件被定義,data 必須聲明為傳回一個初始資料對象的函數,因為元件可能被用來建立多個執行個體,如果 data 仍然是一個純碎的對象,則所有的執行個體将被共享引用同一個資料對象。通過提供 data 函數,每次建立一個新執行個體後,我們能夠調用 data 函數,進而傳回初始資料的一個全新副本資料對象。
2.props
props 可以是數組或者對象,用于接收來自父元件的資料。props 中使用對象可以配置進階選項,類型檢測,自定義驗證,設定預設值
可以使用以下選項
type:可以是原生構造函數中的一種:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定義構造函數,或上述内容組成的數組。會檢查一個 prop 是否是給定的類型,否則抛出警告。
default:為 prop 指定一個預設值。如果該 prop 沒有被傳入,則換做用這個值。對象或數組的預設值必須從一個工廠函數傳回
required:Boolean 定義該 prop 是否是必填項
validator:function 自定義驗證函數會将該 prop 的值作為唯一的參數帶入。傳回 false 就給預設值,控制台有警告
props: {
// 檢測類型
height: Number,
// 檢測類型 + 其他驗證
age: {
type: Number,
default: 0,
required: true,
validator: function (value) {
return value >= 0
}
}
}
3.propsData
隻用于 new 建立的執行個體中,建立執行個體時傳遞 props,主要作用時友善測試(開發的過程中基本用不到)
4.computed 計算屬性
計算屬性将被混入到 Vue 執行個體中,所有 geter 和 setter 的 this 上下文自動地綁定為 Vue 執行個體
注意如果你為一個計算屬性使用了箭頭函數,則 this 不會指向這個元件的執行個體,不過你仍然可以将其執行個體作為函數的第一個參數來通路。
計算屬性的結果會被緩存,除非依賴的響應式 property 變化才會重新計算。注意,如果某個依賴(必須非響應式 property)在該執行個體範疇之外,則計算屬性是不會被更新的。
<p>a + b 的結果是:{{ count }}</p>
computed: {
count(){
return this.a + this.b
}
}
計算屬性 vs 方法
<p>a + b 的結果是:{{ count() }}</p>
methods: {
count(){
return this.a + this.b
}
}
我們可以将同一函數定義為一個方法而不是一個計算屬性,兩種方式的最終結果确實是完全相同的。不同的是計算屬性是基于他們的響應式依賴進行緩存的。隻在相應響應式依賴發生改變時他們才會重新計算求值。就是說隻要 a 或者 b 還沒有發生改變,多次通路 count 計算屬性會立即傳回之前的計算結果,而不必再次執行函數。
相比之下,每當觸發重新渲染時,調用方法将總會再次執行函數,
我們為什麼需要緩存? 假設我們有一個性能開銷比較大的計算屬性 A,他需要周遊一個巨大的數組并做大量的計算,然後我們可能有其他的計算屬性依賴于 A。如果沒有緩存我們将不可避免的多次執行 A 的getter。如果不希望有緩存出現,請用方法代替。
計算屬性的 setter
計算屬性預設隻有 getter ,不過在需要時也可以提供一個 setter
computed: {
str: {
get: function() {
return this.a + this.b
},
set: function(newVlaue) {
var abs = newValue.split(' ')
this.a = abs[0]
this.b = abs[abs.length - 1]
}
}
}
現在運作 this.str = '2 3 4 5'時,setter 會被調用,this.a 和 this.b 也會相應地被更新
5.methods 事件處理
在模闆中通過 v-on 定義方法名,在 methods 中定義方法
有時在内聯語句處理器中通路原始的 DOM 事件,可以用特殊變量 $event 把它傳入方法
<button @click="count(200, $event)">按鈕</button>
<button @click="count2">按鈕2</button>
methods: {
count: function(val, event) {
if(event) {
event.preventDefault()
}
// ...
},
count2: function(event) {// 如果模闆中什麼都不傳遞,在這裡可以預設直接接受一個參數就是 dom 對象
if(event) {
event.preventDefault()
}
// ...
}
}
6.watch 監聽器
一個對象,鍵是需要觀察的表達式,值是對應回調函數,值也可以是方法名,或者包含選項的對象。Vue 執行個體将會在執行個體化時調用 $watch(),周遊 watch 對象的每一個屬性
值是包括選項的對象,有三個選項
handler:回調函數,即監聽到變化時應該執行的函數
deep: Boolean,确認是否深度監聽
為了發現對象内部值的變化,可以在選項參數中指定 deep: true 注意監聽數組的變更不需要這麼做
immediate:Boolean,為true時,将立即以表達式的目前值出發回調(進入頁面就開始監聽)
watch: {
a(){},
// 該回調會在任何被監聽的對象 property 改變時被調用,不論其被嵌套多深
b: {
handler: function(){},
deep: true
},
// 該回調将會在偵聽開始之後立即調用
c: {
handler: function(),
immediate: true
},
// 可以傳入回調數組,他們會被一一調用
d: [
handle1,
function handle2(){},
{
handler: function handle3(){}
}
]
}
二、選項 / DOM
在開發的過程中很少需要考慮這些東西,看看官網熟悉一下
到官網去了解一下
三、選項 / 生命周期鈎子
每個 Vue 執行個體在被建立時都要經過一系列的初始化過程,設定資料監聽,編譯模闆,執行個體挂載到 DOM ,資料變化時更新 DOM 等,這裡面有一系列的函數,稱之為生命周期鈎子
1.beforeCreate
在執行個體初始化之後,資料觀測(data observer) 和 event/watcher 事件配置之前被調用,此時元件的選項對象還沒有建立,el 和 data 并未初始化,是以無法通路 methods,data,computed 等上的方法和資料
2.created
在執行個體建立完成之後被立即調用。這一步,執行個體已經完成以下配置:資料觀測(data observer),property 和方法的運算,watch/event 事件回調。然而挂載階段還沒開始,$el property 目前尚不可用。這是一個常用的生命周期,這裡面可以調用 methods 中的方法,改變 data 中的資料,并且修改可以通過 vue 的響應式綁定展現在頁面上,擷取 計算屬性 等等,通常我們在這裡請求接口中的資料,
3.beforeMount
在挂在之前被調用,相關的 render 函數首次被調用,執行個體已經完成一下的配置:編譯模闆,把 data 裡面的資料和模闆生成 html,完成了 el 和 data 初始化,注意此時還沒有挂載到 html 頁面上
4.mounted
執行個體被挂載後被調用,這時 el 被新建立的 vm.$el 替換了。如果跟執行個體挂載到了一個文檔内的元素上,當 mounted 被調用時 vm.$el 也在文檔内
注意 mounted 不會保證所有的子元件也一起被挂載,如果希望等到整個視圖都渲染完畢,可以在 mounted 内部使用 vm.$nextTick
mounted(){
this.$nextTick(function(){
// ...
})
}
5.beforeUpdate
資料更新時調用,發生在虛拟 DOM 打更新檔之前,這裡适合在更新之前通路現有的 DOM,比如手動移除已添加的事件監聽器。
該鈎子在伺服器端渲染期間不被調用,因為隻有初次渲染會在服務端進行
6.updated
由于資料更改導緻的虛拟 DOM 重新渲染和打更新檔,在這之後會調用該鈎子。
當這個鈎子被調用時,元件 DOM 已經更新,是以你現在可以執行依賴于 DOM 的操作。然而大多數情況下,你應該避免在此期間更改狀态。如果要相應狀态改變,通常最好使用 計算屬性 或 watcher 取而代之。
注意 updated 不會保證所有子元件也都一起被重繪。如果你希望等到整個視圖都重繪完畢,可以在 updated 裡使用 vm.$nextTick(同上)
7.activated
被 keep-alive 緩存的元件激活時調用
該鈎子在伺服器端渲染期間不被調用
8.deactivated
被 keep-alive 緩存的元件停用時被調用
該鈎子在伺服器端渲染期間不被調用
9.beforeDestroy
執行個體銷毀之前調用。在這一步,執行個體仍然完全可用
該鈎子在伺服器端渲染期間不被調用
10.destroyed
執行個體銷毀後調用,該鈎子被調用後,對應 Vue 執行個體的所有指令都被解綁,所有的事件監聽器被移除,所有的子執行個體也都被銷毀
該鈎子在伺服器端渲染期間不被調用
11.errorCaptured
當捕獲一個來自子孫元件的錯誤時被調用,此鈎子會收到三個參數:錯誤對象、發生錯誤的元件執行個體和一個包含錯誤來源資訊的字元串。此鈎子傳回 false 以阻止該錯誤繼續向上傳播
可以在此鈎子中修改元件的狀态。是以在捕獲錯誤時,在模闆或渲染函數中有一個條件判斷來繞過其他内容就很重要,不然該元件可能會進入一個無限的渲染循環
錯誤傳播規則
1.預設情況下,如果全局的 config.errorHandler 被定義,所有的錯誤仍會發送它,是以這些錯誤仍然會向單一的分析服務的地方進行彙報。
2.如果一個組建的繼承或父級從屬鍊路中存在多個 errorCaptured 鈎子,則它們将會被相同的錯誤一一喚起
3.如果此 errorCaptured 鈎子自身抛出了一個錯誤,則這個新錯誤和原本被捕獲的錯誤都會發送給全局的 config.errorHandler
4.一個 errorCaptured 鈎子能夠傳回 false 以阻止錯誤繼續向上傳播。本質上是說’這個錯誤已經被搞定且應該被忽略‘。他會阻止其他任何會被這個錯誤喚起的 errorCaptured 鈎子和全局的 config.errorHandler
四、選項 / 資源
1.directives 自定義指令
2.filters 過濾器
3.components 元件
directives、filters、components 詳情在這裡有介紹 vue API 知識點(1)---全局 API 總結
五、選項 / 組合
1.parent
指定已建立的執行個體之父示例,在兩者之間建立父子關系。子執行個體可以用 this.$parent 通路父執行個體,子執行個體被推入到父執行個體的 $children 數組中
我們在開發中,基本上不會使用到 $parent 和 $children 。更多的是使用 props 和 events 實作父子元件通信,
2.mixins 混入
3.extends
允許聲明擴充另一個元件,而無需使用 Vue.extend。這主要是為了便于擴充單檔案元件
這和 mixins 有點類似
mixins、extends 在這篇文章中有詳細的介紹 vue API 知識點(1)---全局 API 總結
4.provide / inject
provide 和 inject 主要在開發高階插件/元件庫時使用。并不推薦用于普通應用程式代碼中。
這對選項需要一起使用,以允許一個祖先元件向其所有子孫後代注入一個依賴,不論元件層次有多深,并在其上下遊關系成立的時間裡始終生效。
解析:就是元件的引入層次過多,我們的子孫元件想要擷取祖先元件的資源,可以不使用 props 的方式依次傳遞給子孫元件,層次太多,代碼結構容易混亂。那麼就可以使用 provide/inject 來做傳遞
官方注解
provide 選項應該是一個對象或傳回一個對象的函數。該對象包含可注入其子孫的 property。在該對象中你可以使用 Symbols 作為key,但是隻在原生支援 Symbol 和 Reflect.ownKeys 的環境下可工作
inject 選項應該是一個字元串數組或一個對象,對象的key是本地的綁定名,
value 是 在可用的注入内容中搜尋用的 key(字元串或 Symbol),或一個對象,該對象的
from property 是在可用的諸如内容中搜尋用的 key(字元串或 Symbol)
default property 是降級情況下使用的 value
個人解析
provide 是一個對象,或者是一個傳回對象的函數,裡面就包含要給子孫後代的東西,也就是屬性和屬性值
inject 一個字元串數組,或者是一個對象。屬性值可以是一個對象,包含 from 和 default 預設值
const Child = {
inject: {
foo: {
from: 'bar',
default: 'foo'
}
}
}
from 表示在可用的注入内容中搜尋用的 key,default 當然就是預設值
注意:provide 和 inject 綁定并不是可響應的。這是刻意為之的,然而,如果你傳入了一個可監聽的對象,那麼其對象的 property 還是可響應的
官方示例
// 父元件
var Provider = {
provide: {
name: 'zhangning'
},
// ...
}
// 子元件注入
var Child = {
inject: ['name'],
created() {
console.log(this.name) // => 'zhangning'
}
}
利用 es 中的 Symbols、函數 provide 和對象 inject
const a = Symbol();
const Parent = {
provide(){
return {
[a]: 'zhangning187'
}
}
}
const Child = {
inject: { a },
// ...
}
在新版本中,使用一個注入的值作為一個 property 的預設值
const Child = {
inject: ['name'],
props: {
bar: {
default() {
return this.name
}
}
}
}
使用一個注入的值作為資料入口
const Child = {
inject: ['name'],
data() {
return {
bar: this.name
}
}
}
如果它需要從一個不同名字的 property 注入,則使用 from 來表示其源 property
const Child = {
inject: {
from: 'bar',
default: 'name'
}
}
與 prop 的預設值類似,你需要對非原始值使用一個工廠方法
const Child = {
inject: {
name: {
from: 'bar',
default: () => [1, 2, 3]
}
}
}
在日常的開發中,我們經常會使用 Vuex 做狀态管理,但是 vuex 有時候太過于繁瑣。如果我們不想使用 vuex,這個時候我們就可以使用 provide/inject 這個方式來代替vuex,在跟元件中傳入變量,然後在後代元件中使用即可
// 在跟元件中提供一個非響應式變量給後代元件
export default {
provide() {
return {
text: 'zhangning'
}
}
}
// 後代元件注入
export default {
inject: ['text'],
created() {
this.text = 'zhangning187'// 在我們使用 text 的時候它依然是 zhangning,而不是zhangning187
}
}
上面已經講過,provide 和 inject 綁定并不是可響應的,這是可以為之。當然我們也可以傳入一個可響應的對象,那麼它的屬性也就是可響應的了
也就是說,Vue 不會對 provide 中的變量進行響應式處理。是以要想 inject 接受的變量是響應式的,provide 提供的變量本身就需要是響應式的。
由于元件内部的各種狀态就是可響應式的,是以我們直接在根元件中将元件本身注入 provide,此時,我們可以在後代元件中任意通路根元件中的所有狀态,根元件就成為了全局狀态的容器
// 根元件提供将自身提供給後代元件
export default {
provide() {
return {
app: this
}
},
data() {
return {
text: 'zhangning'
}
}
}
// 後代元件 注入
export default {
inject: ['app'],
data(){
return{}
},
created: {
this.app.text = 'zhangning187'// 此時使用 text,它的值就是zhangning187
}
}
當然,我們也可以通過 $root 來擷取根節點,但是在團隊開發的過程中,如果所有的全局變量都統一定義在根元件中并不合适,而使用 provide/inject 不同子產品的入口元件傳給各自的後代元件可以完美解決這個問題
Vuex 和 provide/inject 差別在于,Vuex 中的全局狀态的每次修改都是可以追蹤回溯的,而 provide/inject 中變量的修改是無法控制的,通俗說就是,你不知道是哪個元件修改了這個全局狀态。
provide/inject 破壞了我們的單向資料流原則。如果多個後代元件同時依賴于一個祖先元件提供的狀态,那麼隻要有一個元件修改了這個狀态,則所有元件都會受到影響。這個使耦合度增加了,讓我們的資料變化不可控,在多人的開發過程中,這個可能會變得特别混亂。
以上看起來使用 provide/inject 做全局狀态管理好像很危險,是以我們要謹慎使用這個方式。
但是在元件開發的時候,vue 官方提倡我們使用這種方法。例如 elment-ui
六、選項 / 其他
1.name
隻有作為元件選項時起作用
允許元件模闆遞歸地調用自身,注意,元件在全局用 Vue.component() 注冊時,全局 ID 自動作為元件的 name
指定 name 選項的好處就是便于調試,有名字的元件有更友好的警告資訊,當在 vue-devtools 下,未命名元件将顯示成<AnonymousComponent>,這很沒有語義,通過提供 name 選項,可以獲得更有語義資訊的元件樹
2.delimiters
了解一下就行,通常不會去更改插入分隔符
類型 Array<string>
預設值 ["{{", "}}"]
限制 這個選項隻在完整建構版本中的浏覽器内編譯時可用
改變純文字插入分隔符
示例
new Vue({
delimiters: ["${", "}"]
})
// 分隔符變成了 ES6 模闆字元串的風格
3.functional
了解一下,通常用不到
類型 Boolean
使元件組狀态(沒有 data)和無執行個體(沒有 this 上下文)。他們用一個簡單的 render 函數傳回虛拟節點,是他們渲染的代價更小
4.model
允許一個自定義元件在使用 v-model 時定制 prop 和 event。預設情況下,一個元件上的 v-model 會把 value 用作 prop 且把 input 用作 event,但是一下輸入類型比如單選框和複選框按鈕可能想使用 value prop 來達到不同的目的。使用 model 選項可以回避這些情況産生的沖突
// 定義一個元件
Vue.component('my-check', {
model: {
prop: 'checked',
event: 'change'
},
props: {
value: String,
checked: {
type: Number,
default: 0
}
}
})
使用
<my-check v-model='foo' value='some value'></my-check>
以上代碼相當于
<my-check :checked='foo' @change='value=>{foo = val}' value='some value'></my-check>
我們先了解一下 input 中的 v-model 是怎麼實作雙向綁定的。
<input type='text' v-model='msg'>
v-model 隻是文法糖真正的實作方式
<input type='text' :value='msg' @input='msg=$event.target.value'>
真正的雙向綁定是通過監聽 input 事件
v-model 在内部為不同的輸入元素使用不同的屬性并抛出不同的事件
text 和 textarea 元素使用 value 屬性和 input 事件
checkbox 和 radio 使用 checked 屬性和 change 事件
select 使用 value 和 change 事件
我們可以自定義輸入框元件的 v-model,雙向綁定
Vue.component('my-input', {
template: `<input :value='value' @input='updateValue($event.target.value)' type='text'></input>`,
props: ['value'],
methods: {
updateValue(val) {
this.$emit('input', val)
}
}
})
let app = new Vue({
el: '#app',
data(){
message: ''
},
methods: {
handleInput(val) {
this.message = val
}
}
})
<div id='app'>
<my-input :value='message' @input='handleInput'></my-input>
</div>
上面的示例我們可以了解到,預設情況下,一個元件上的 v-model 會把 value 用作 prop 且把 input 用作 event,是以當我們在一個自定義元件上使用 v-model 并不能實作雙向綁定,因為自定義的元件并沒有預設的 value 和 input 事件,在使用時,我們需要按照上面那樣顯式的去聲明定義這些東西,這時,選項 model 就派上用場了,在定義元件的時候指定 prop 的值和監聽的事件(看到這裡,上面寫的官網給出的例子也應該可以看明白了)
舉例
Vue.component('my-input', {
model: {
prop: 'uname',
event: 'handleChange'
},
props: {
uname: {
type: String,
default: 'zhangning'
}
},
methods: {
updateVal(val) {
this.$emit('handleChange', val)
}
}
})
模闆
<template>
<div>
<input type='text' :value='uname' @input='updateVal($event.target.value)'>
</div>
</template>
使用元件
<my-input v-model='name' value='some value'></my-input>
等價于
<my-input :uname='name' @handleChange='val=>{foo = val}' value='some value'></my-input>
上面的示例中我們就可以在自定義的元件中使用 v-model 來進行雙向綁定了(多看一下示例就明白了)