英文博客原文:Vue.js: a (re)introduction
Vue.js 是一個(gè)用來開發(fā) web 界面的前端庫余赢。它也有配套的周邊工具。如果把這些東西都算在一起捧弃,那么你也可以叫它一個(gè)『前端框架』跟压。但我個(gè)人更傾向于把它看做是一套可以靈活選擇的工具組合。如果你到現(xiàn)在都還沒聽說過 Vue.js蛤奥,你心里可能在想:前端的幺蛾子就是多佳镜,怎么又來一個(gè)框架?其實(shí) Vue.js 已經(jīng)開發(fā)了兩年多了凡桥。第一次公開發(fā)布則是在 2014 年 2 月蟀伸。這兩年間它一直在不斷進(jìn)化,今天也已經(jīng)有許多人在生產(chǎn)環(huán)境中使用它缅刽。
所以啊掏,Vue.js 到底提供了什么?和其他框架又有何不同衰猛?在已經(jīng)有了 Angular迟蜜、React、Ember 的情況下啡省,為什么要關(guān)注 Vue 娜睛?這篇文章會(huì)簡要地介紹 Vue 的特點(diǎn),希望讀者看完以后能自行判斷卦睹。
響應(yīng)式編程
都說保持狀態(tài)和視圖的同步是困難的畦戒。真的是這樣么?
讓我們從最基本的任務(wù)說起:展示數(shù)據(jù)结序。假設(shè)我們有這樣一個(gè)對(duì)象:
var object = {
message: 'Hello World!'
}
以及這樣的模板:
<div id="example">
{{ message }}
</div>
我們可以用 Vue 這樣將兩者綁定:
new Vue({
el: '#example',
data: object
})
看上去和渲染模板沒什么兩樣障斋。那么當(dāng)我們改動(dòng)了 object 時(shí),如何更新視圖呢徐鹤?答案是... 你什么都不用做垃环。Vue 已經(jīng)把 object 對(duì)象改造成了一個(gè)『響應(yīng)式對(duì)象』。當(dāng)你修改 object.message 的值時(shí)返敬,渲染的 HTML 會(huì)自動(dòng)更新遂庄。更關(guān)鍵的是,你不需要擔(dān)心你是否因?yàn)槭窃谝粋€(gè) timeout 里面修改了狀態(tài)而需要調(diào)用 $apply劲赠,或是需要調(diào)用 setState()涧团,也不需要給 Flux store 上偵聽一堆事件只磷,更不需要?jiǎng)?chuàng)建一些框架專有的可觀察對(duì)象,比如 ko.observable() 或是 Ember.Object.create() ... It just works泌绣。
Vue 也提供了無縫的『計(jì)算屬性』:
var example = new Vue({
data: {
a: 1
},
computed: {
b: function () {
return this.a + 1
}
}
})
// example 實(shí)例會(huì)同時(shí)代理 a 和 b 這兩個(gè)屬性.
example.a // -> 1
example.b // -> 2
example.a++
example.b // -> 3
這里钮追,計(jì)算屬性 b 會(huì)將 a 作為一個(gè)依賴進(jìn)行追蹤,每當(dāng) a 變化阿迈,b 也自動(dòng)跟著變化元媚。你不需要特意去聲明 b 的依賴,因?yàn)檫@本來就不應(yīng)該由你來做苗沧。
組件化
你這個(gè)做小 demo 還不錯(cuò)刊棕,可是大項(xiàng)目呢?
在如何組織復(fù)雜界面的問題上待逞,Vue 和 React 可以說是異曲同工:一切都是組件甥角。我們可以把一開始的那個(gè)例子做成一個(gè)可復(fù)用的組件:
var Example = Vue.extend({
template: '<div>{{ message }}</div>',
data: function () {
return {
message: 'Hello Vue.js!'
}
}
})
// 將該組件注冊(cè)為 <example> 標(biāo)簽
Vue.component('example', Example)
這樣一來我們就可以在其他組件的模板里這樣使用它:
<example></example>
組件可以套其他組件,最終形成一個(gè)代表了你的 UI 視圖的樹狀結(jié)構(gòu)识樱。為了讓組件之間能夠有效的進(jìn)行動(dòng)態(tài)組構(gòu)嗤无,Vue 組件可以:
- 用 props 來定義如何接收外部數(shù)據(jù);
- 用自定義事件來向外傳遞消息怜庸;
- 用 <slot> API 來將外部動(dòng)態(tài)傳入的內(nèi)容(其他組件或是 HTML)和自身模板進(jìn)行組合当犯。
這里就不過多深入細(xì)節(jié)了。有興趣的同學(xué)可以自行查閱官方文檔割疾。
模塊化
都已經(jīng) 2015 年了嚎卫,再不模塊化都不好意思跟人打招呼。
讓我們用一個(gè)模塊打包工具來配合 Vue.js宏榕,比如 Webpack 或者 Browserify拓诸,然后再加上 ES2015。每一個(gè) Vue 組件都可以看做一個(gè)獨(dú)立的模塊麻昼。同時(shí)因?yàn)?Vue 會(huì)自動(dòng)用 Vue.extend 把對(duì)象轉(zhuǎn)化為組件構(gòu)建函數(shù)恰响,我們?cè)谀K里不需要自己調(diào)用 Vue.extend,直接導(dǎo)出一個(gè)對(duì)象即可:
// ComponentA.js
export default {
template: '<div>{{ message }}</div>',
data () {
return {
message: 'Hello Vue.js!'
}
}
}
// App.js
import ComponentA from './ComponentA'
export default {
// use another component, in this scope only.
// ComponentA maps to the tag <component-a>
components: { ComponentA },
template: `
<div>
<p>Now I'm using another component.</p>
<component-a></component-a>
</div>
`
}
看上去還不錯(cuò)涌献。但如果能把一個(gè)組件的模板、樣式和 JavaScript 邏輯都放在同一個(gè)文件里首有,并且有正確的語法高亮燕垃,豈不是更妙?只要配上 vue-loader 或是 vueify井联,我們就能做到:
<!-- MyComponent.vue -->
<!-- css -->
<style>
.message {
color: red;
}
</style>
<!-- template -->
<template>
<div class="message">{{ message }}</div>
</template>
<!-- js -->
<script>
export default {
props: ['message'],
created() {
console.log('MyComponent created!')
}
}
</script>
等一下卜壕!這不就是 Web Components 嗎!而且你的 CSS 依然是全局的呢烙常!
好吧轴捎,這確實(shí)很像是閹割版的 Web Components鹤盒,但是:
- Vue 文件格式可以支持局部 CSS,只要在 <style> 標(biāo)簽上加上一個(gè) scoped 屬性侦副。并且一個(gè)組件的局部 CSS 不會(huì)像單純的選擇器嵌套那樣『滲透』到它包含的子組件當(dāng)中去侦锯。
- 每一個(gè) Vue 組件最終都被編譯為純粹的 JavaScript 模塊,并且不需要任何瀏覽器 polyfill 即可支持到最低 IE9秦驯。如果你想尺碰,你也可以把它包在一個(gè)原生的自定義元素中。
- Vue 文件的 <script> 默認(rèn)支持 ES2015译隘。
- 你可以在每一個(gè)語言塊中使用任何你想用的預(yù)處理器亲桥。
- 當(dāng)使用 Webpack + vue-loader 時(shí),你可以借助 Webpack 的強(qiáng)大功能將靜態(tài)資源作為模塊依賴來處理固耘。
所以题篷,只要你想,你就可以寫這個(gè)樣子的 Vue 組件:
哦對(duì)了厅目,我有沒有提到番枚,Vue 組件支持熱替換?
動(dòng)畫
Vue 能用來做酷炫的東西不璧瞬?
Vue 自帶簡潔易用的過渡動(dòng)畫系統(tǒng)户辫。有很多獲獎(jiǎng)的互動(dòng)類網(wǎng)站是用 Vue 開發(fā)的。
Vue 的反應(yīng)式系統(tǒng)也使得它可以用來開發(fā)高效的數(shù)據(jù)驅(qū)動(dòng)的逐幀動(dòng)畫嗤锉。這一類逐幀動(dòng)畫在基于臟檢查或是 Virtual DOM 的框架中渔欢,往往會(huì)導(dǎo)致性能問題,因?yàn)榧词怪皇歉牧艘粋€(gè)值瘟忱,整個(gè)所處的子樹(scope 或是 component)都需要重新計(jì)算奥额。而 Vue 則是改了多少,計(jì)算多少访诱,不會(huì)有無謂的浪費(fèi)垫挨。在小 demo 中,臟檢查或是 Virtual DOM 往往也足夠快触菜,但是在大型應(yīng)用中可就不一定了九榔。而且,即使足夠快涡相,那些浪費(fèi)的計(jì)算也會(huì)無謂地消耗用戶設(shè)備的電池哲泊。雖然在 React 中可以通過 shouldComponentUpdate 或是 Immutable data 來優(yōu)化,但這都是額外的開發(fā)成本 - 相比之下催蝗,Vue 在此類用例中默認(rèn)就是最優(yōu)化狀態(tài)切威。
路由
做單頁應(yīng)用,沒有路由怎么行丙号?
和 React 一樣先朦,Vue 本身是不帶路由功能的缰冤。但是,有 vue-router 這個(gè)可選的庫來配合喳魏。vue-router 讓你可以將嵌套的路徑映射到嵌套的組件棉浸,并且提供了細(xì)致的路徑跳轉(zhuǎn)控制。這里是個(gè)簡單的例子:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './app.vue'
import ViewA from './view-a.vue'
import ViewB from './view-b.vue'
Vue.use(VueRouter)
const router = new VueRouter()
router.map({
'/a': { component: ViewA },
'/b': { component: ViewB }
})
router.start(App, '#app')
app.vue 的模板:
<div>
<h1>This is the layout that won't change</h1>
<router-view><!-- matched component renders here --></router-view>
</div>
如果你想看一個(gè)更全面的實(shí)例截酷,可以參考 vue-hackernews涮拗。這個(gè)小應(yīng)用用到了 Vue, vue-router, Webpack 和 vue-loader。
穩(wěn)定性
這是個(gè)個(gè)人項(xiàng)目迂苛,會(huì)不會(huì)不穩(wěn)定啊三热。
是的,這是個(gè)個(gè)人項(xiàng)目三幻,背后并沒有大公司支持的全職團(tuán)隊(duì)就漾。但是,數(shù)據(jù)往往更有說服力念搬。從 0.11 版本開始抑堡,Vue 的每一個(gè) commit 都保持了 100% 的測試覆蓋率,并且將一直保持朗徊;GitHub 上的 1400 多個(gè) issue 平均在 13 小時(shí)內(nèi)關(guān)閉首妖。在我寫下這篇文章的同時(shí),尚未修復(fù)的可重現(xiàn)的 bug 數(shù)量為:零爷恳。
Vue 近日剛剛發(fā)布了 1.0有缆,現(xiàn)在已經(jīng)適合應(yīng)用于生產(chǎn)環(huán)境中。如果你是從 0.12 升級(jí)到 1.0温亲,則有配套的升級(jí)版本棚壁,全面兼容 0.12 并且?guī)в屑嫒菪缘奶崾揪妗R院蟮乃袔в胁患嫒葑兓陌姹菊恍椋紩?huì)用這樣的方式升級(jí)袖外。
希望這篇文章讓你對(duì) Vue 有了一個(gè)比較大致的了解。我相信相對(duì)于市面上的現(xiàn)有方案魂务,Vue 有著其獨(dú)特的存在價(jià)值曼验。