元件系統
元件可以擴充套件 HTML
元素,封裝可重用的程式碼。
vue.js的核心元件:
- 模板(template)——模板宣告瞭資料和最終展現給使用者的DOM之間的對映關係。
- 初始資料(data)——一個元件的初始資料狀態。對於可複用的元件來說,通常是私有的狀態。
- 接受的外部引數(props)——元件之間透過引數來進行資料的傳遞和共享。引數預設是單向繫結(由上至下),但也可以顯式宣告為雙向繫結。
-
方法(methods)——對資料的改動操作一般都在元件的方法內進行。可以透過
v-on
指令將使用者輸入事件和元件方法進行繫結。 -
生命週期鉤子函式(lifecycle hooks)——一個元件會觸發多個生命週期鉤子函式,比如
created
、attached
、destroyed
等。在這些鉤子函式中,我們可以封裝一些自定義的邏輯。和傳統的MVC相比,這可以理解為Controller
的邏輯被分散到了這些鉤子函式中。 - 私有資源(assets):Vue.js當中將使用者自定義的指令、過濾器、元件等統稱為資源。由於全域性註冊資源容易導致命名衝突,一個元件可以宣告自己的私有資源。私有資源只有該元件和它的子元件可以呼叫。
- 除此之外,同一棵元件樹之內的元件之間還可以透過內建的事件API來進行通訊。Vue.js提供了完善的定義、複用和巢狀元件的API,讓開發者可以像搭積木一樣用元件拼出整個應用的介面。這個思路的可行性在Facebook開源的React當中也得到了印證。
基於構建工具的單檔案元件格式
Vue.js的核心庫只提供基本的API,本身在如何組織應用的檔案結構上並不做太多約束。但在構建大型應用時,推薦使用 Webpack+vue-loader
這個組合以使針對元件的開發更高效。
Webpack是由Tobias Koppers開發的一個開源前端模組構建工具。它的基本功能是將以模組格式書寫的多個JavaScript檔案打包成一個檔案,同時支援CommonJS和AMD格式。但讓它與眾不同的是,它提供了強大的loader API來定義對不同檔案格式的預處理邏輯,從而讓我們可以將CSS、模板,甚至是自定義的檔案格式當做JavaScript模組來使用。Webpack 基於loader還可以實現大量高階功能,比如自動分塊打包並按需載入、對圖片資源引用的自動定位、根據圖片大小決定是否用base64內聯、開發時的模組熱替換等等,可以說是目前前端構建領域最有競爭力的解決方案之一。
其他特性
Vue.js還有幾個值得一提的特性:
-
非同步批次DOM更新:當大量資料變動時,所有受到影響的
watcher
會被推送到一個佇列中,並且每個watcher
只會推進佇列一次。這個佇列會在程序的下一個 “tick” 非同步執行。這個機制可以避免同一個資料多次變動產生的多餘DOM操作,也可以保證所有的DOM寫操作在一起執行,避免DOM讀寫切換可能導致的layout。 -
動畫系統:Vue.js提供了簡單卻強大的動畫系統,當一個元素的可見性變化時,使用者不僅可以很簡單地定義對應的CSS
Transition
或Animation
效果,還可以利用豐富的JavaScript鉤子函式進行更底層的動畫處理。 - 可擴充套件性:除了自定義指令、過濾器和元件,Vue.js還提供了靈活的mixin機制,讓使用者可以在多個元件中複用共同的特性。
使用Prop傳遞資料
元件例項的作用域是孤立的。這意味著不能(也不應該)在子元件的模板內直接引用父元件的資料。要讓子元件使用父元件的資料,我們需要透過子元件的 props
選項。
子元件要顯式地用 props
選項宣告它期待獲得的資料。
Vue.component({
props: ['message'],
template: '<span>{{message}}</span>'
});
父子元件通訊
Vue 中子元件可以透過透過事件和父元件進行通訊的。向父元件發訊息是透過 this.$dispatch
,而向子元件傳送訊息是透過 this.$boardcast
。
資料繫結的實現原理
Vue 把雙向繫結稱作 reactive,可以翻譯為響應式資料繫結。內部是透過 ES5 定義的 getter
和 setter
方法實現的,所以不支援 IE8 及以下瀏覽器,這種實現方式有兩個容易犯錯的地方:
- 如果在 data 上直接新增和刪除屬性是無法被檢測到的,一般刪除是不會的,但是可能會動態新增,這個時候應該透過
vm.$set(“name”, value)
的方式來新增。 - 無法檢測到物件內部的變化,也就是隻能檢測 data 的屬性變化,如果
data.a
是一個物件,那麼data.a.b = 1
這種變化是無法被檢測到的。這種情況下應該建立一個新的物件並賦值給 data.a 就行了。
非同步更新機制
Vue 對DOM的更新是非同步的! 這個非同步是在一個非同步佇列中進行的,不過這個非同步佇列會在當前的 Event Loop
中執行完,所以如果修改了 Data 立刻去DOM中做查詢操作是不對的,這個時候DOM還沒有更新,正確的做法是這樣做:
vm.msg = 'new message' // change data
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
或者這樣:
vm.$nextTick(function () {
this.$el.textContent === 'new message' // true
})