在公司裏幫項目組裏開發後臺系統的前端項目也有一段時間了。 vue這種數據驅動,組件化的框架和react很像,
從一開始的快速上手基本的開發,到後來開始自定義組件,對element UI的組件二次封裝以知足項目需求,期間也是踩了很多坑。
因爲未來很長一段時間可能不再會接觸前端了,趁着如今對vue還很熟練的時候,趕忙將這期間的收穫記錄下來。css
按照個人理解,vue的特色在於,高層次的抽象模型,組件化,數據驅動與響應式。
<!--more-->html
注意:本文中全部涉及到{ {
的,實際上不包括中間的空格,由於hexo會無腦把這個語法當成hexo的一種特殊語法 前端
簡單的來講,vue是一套用於前端開發的框架。
學習一門技術首先應該對該技術有着一個清晰正確的認識和思路,不然猶如浮沙之上建高樓。下面就來談談我對vue這個框架的理解。vue
vue它的驚豔之處在於,對上,它提供了一套很是優秀的與傳統前端大相徑庭的前端開發模型,對下,它屏蔽了傳統前端開發的各類醜陋的技術。
在實現複雜的頁面需求時,vue幫你從傳統前端的各類HACK般的奇淫技巧解脫出來,vue提供的抽象開發模型擁有強大的 表達能力,可以如絲順滑般的完成各類複雜的需求。java
總而言之,vue之於傳統前端,相似C語言之於彙編語言,就像C語言提供了一個強大的表達能力強的語言模型同樣,vue一樣提供了一個強悍的表達前端的框架模型,這是抽象的威力。
所以,學習vue的80%的重心,都在學習這個強悍的vue模型上。python
從我我的對vue的理解,它的幾個重要特色有:react
它還有幾個其它的的特色:webpack
下面的例子定義了一個簡單的組件,x-my-component。
因爲是須要兼容easy UI的後臺系統,該項目並不能使用到webpack + babel + es6等技術,所以我在vue上的經驗大都是使用原生的js編寫的,git
<div id="x-my-component"> <div> { { message }} </div> </div> <script> Vue.component('x-my-component', { template: '#x-my-component', data: function () { return { message: 'Hello Vue!' }; } }); </script>
{ { message }}
表示將數據message綁定到視圖的這個地方來。x-my-component
全局組件。因爲vue是組件化的,組件能夠層層嵌套。不過,最終的根節點得是app節點,這樣才能渲染出結果。它的定義方式不太相同:es6
<div id="app"> <x-my-component></x-my-component> </div> <script> var app = new Vue({ el: '#app', }); </script>
從數據驅動的觀點,咱們很容易分析出數據流向:
數據源 --> vue對象 --> DOM
<div id="x-my-component"> <span v-bind:title="message"> { { message }} { { message.split('').reverse().join('') }} </span> <span :title="message"> </span> <div v-html="rawHtml"></div> </div> <script> Vue.component('x-my-component', { template: '#x-my-component', data: function () { return { message: 'Hello Vue!', rawHtml: '<s>deleted!</s>' }; } }); </script>
{ {}}
的語法就能夠了。v-bind
語法。上面將 message
數據綁定到了title屬性上。v-bind:title
可直接縮寫爲 :title
。-v-html
語法,綁定原始的html數據。在傳統的前端編程中,須要仔細預防的一點是xss攻擊。xss攻擊的原理是:
所以,爲預防xss,任何用戶給定的數據展示到頁面上都須要仔細的處理。可是若是使用vue,就沒必要太操心這個問題。
由於,vue提供了一個更高層次的前端模型,全部的業務代碼都須要經過vue處理。咱們只須要看vue對xss的處理狀況就能夠了。
從上面咱們能夠看到,數據到視圖渲染中必須使用vue的插值語法:
<div id="x-my-component"> <p v-if="seen">如今你看到我了</p> <ol> <li v-for="todo in todos"> { { todo.text }} </li> </ol> </div> <script> Vue.component('x-my-component', { template: '#x-my-component', data: function () { return { seen: true, todos: ["A", "B", "C"] }; } }); </script>
v-if
綁定的數據,控制此元素是否顯示。v-for
綁定的特殊語法,用於控制循環, v-for
的元素會被重複。如上所示,todos是一個數組。上面的例子中能夠數據綁定的語法,實際上,將數據綁定到視圖上的操做並很多見,這些操做,和後端技術經常使用的模樣引擎相似,如python的Jinja2, java的freemarker。
可是,vue的數據綁定的還有一大不一樣點點是 響應式 。
因爲視圖渲染是從數據計算出來的產物,相似一個傳入數據傳出渲染結果的純函數,所以,當數據改變時,渲染結果也會改變,所獲得的結果是頁面展現的界面也會發送改變。
數據綁定還不能徹底走通一個vue組件的數據流程,從上面的數據綁定咱們能夠發現一個事實:
數據由vue對象流向視圖進而渲染出來。
那麼,反過來呢?若是讓數據從頁面流向vue對象?這就是下面要說到的事件處理。
事件處理的數據流向是這樣的:
用戶操做頁面產生數據 --> 頁面 --> vue對象
<div id="x-my-component"> <p>{ { message }}</p> <button v-on:click="reverseMessage">逆轉消息</button> <button @click="reverseMessage">逆轉消息</button> <input v-model="message"> </div> <script> Vue.component('x-my-component', { template: '#x-my-component', data: function () { return { message: 'Hello Vue.js!' }; }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join(''); } } }); </script>
v-on
語法,綁定事件。按鈕的數據傳入到vue對象中。v-on:click
可縮寫成 @click
。v-model
語法,將表單的數據傳入到vue對象中。v-model的數據流動是雙向的,至關於:value數據綁定和@input事件綁定的語法糖。可以與用戶交互的組件都可以產生數據。當用戶操做組件時,組件的相應事件被觸發,進而執行綁定到事件的相應函數。
在函數內部你能夠作任何處理邏輯,好比說改變vue對象記錄的狀態,也就是數據。
那麼,這樣,一個完整的數據流程就跑通了:
咱們知道,數據被綁定到視圖上,視圖自己不存儲狀態,當數據不變時,渲染結果不變;當數據改變時,視圖也須要從新渲染。
好了,如今頭腦裏可能會有一個簡單的思路了:
可是,咱們仔細考察下第三步。瀏覽器的DOM樹改變後,瀏覽器纔會真正的從新渲染這個DOM,計算各類css,各類佈局,層層調用各類繪圖函數從新繪製GUI等等。。。
總而言之,這個步驟是很是很是耗時的。
那麼,一個優化的手段是,儘量讓真正的DOM改變的最少,這樣瀏覽器只須要渲染最少的結果就能達到效果,提高性能。
所以,vurtual DOM就出現了。以下:
能夠看到,整個流程中的一大重點是diff算法。關於DOM的diff算法,我沒有接觸過。。。。。。。
以前研究過文本diff算法是基於LCS算法的動態規劃優化,以後有興趣能夠研究下DOM的diff算法。
從上面咱們知道,當直接設置一個vue屬性的值時,會觸發getter函數。
實際上,getter函數是js的一個機制。在修改數組或對象時,也有相似的機制保證vue能檢測到數據的更新以觸發渲染。
然而,有幾種狀況,因爲js的限制沒法檢測到,實際編程中要特別注意,不然就會感受碰到了一個玄學bug。。。
數組。
this.todos[index] = "B"
。解決方案是:Vue.set(this.todos, index, "B")
,經過vue的函數設置。this.todos.length = 10
。替代方案建議使用不可變數據結構。Vue.set
,刪除的話,可使用不可變數據結構。此篇博文梳理了vue的基本特性,可是對於vue最重量級的功能----組件化,沒有涉及到。對於組件化的相關梳理留到下篇博文梳理。
注:該文於2018-04-09撰寫於個人github靜態頁博客,現同步到個人segmentfault來。