Vue經過Object.defineProperty
定義數據的存取描述符(set和get),來追蹤數據變化。css
在Vue組件初始化時,data下的屬性會被循環遍歷添加上set和get,直到全部的子孫屬性都被添加完。當data的某一屬性值發生了變化(執行set)時,它就會向訂閱了該數據的組件發佈通知,去更新組件。前端
在set裏,組件能夠訂閱該數據變化的通知。vue
set和get叫對象的存取描述符,與存取描述符對應的叫數據描述符。兩者不能共存,默認狀況下,是數據描述符。以下: react
Vue在初始化的時候,會刪掉數據描述符,加上存取描述符。這種方式追蹤數據變化,比React更高效。React用比較引用來追蹤數據變化的方式。在setState的時候,React會用新的state直接替換掉舊state。webpack
即使不改變數據的數值屬性,只要數據的引用地址發生變化了,React組件也會觸發更新。若是不加處理,React組件會多不少次更新。以下面,每次執行handleClick,即使沒有改變數據的數值,(但引用地址發生變化了),組件也會從新渲染。這個渲染是不必的。ios
爲了不組件的這種沒意義的渲染,React推出了PureComponent(純組件),幫助開發者作一層數據的淺比較,僅引用地址發生變化的,就不必從新渲染了。開發的時候,還能夠攔截shouldComponentUpdate生命週期鉤子,顯式地干預是否須要從新渲染組件。在獲得通知數據變化時,React和Vue都採用了vDOM diff算法,各自去更新組件。在追蹤數據變化上,Vue比React更加高效。es6
Vue沒法檢測對象屬性的增刪變化和數組索引長度的變化,在定義object類型的數據時,通常把它下面的屬性也定義了。可是,JS是一門動態語言,能夠不預先定義對象,而且任意地操做對象的屬性。結合v-model使用時,object類型數據的屬性也能夠不用預先定義。web
例如,在表單型的組件裏,一個常見的行爲,不給formData定義title、type等這些屬性,v-model會自動響應用戶輸入,並添加屬性到formData上。ajax
<template>
<div>
<input v-model="formData.title" placeholder="請輸入標題" />
<select v-model="formData.type">
<option value="1">類別</option>
</select>
</div>
</template>
data() {
return {
formData: {}
}
}
複製代碼
props是組件間自上向下通訊數據的方式,子組件逆向修改props,Vue會警告應當避免直接操做props,用data或者computed屬性代替,修改值也不會被傳遞到父組件。算法
然而,藉助v-model,object類型props值,也能夠由子組件傳遞給父組件。簡單類型的props值仍舊沒法修改。
原來,v-model內部檢測到綁定的是對象的key時(indexOf('.') > 0),會調用set方法,更新屬性到對象上,並給組件添加了訂閱事件。
Vue1.0採用的是雙向數據綁定,Vue2.0採用的是單向數據流,即只能父對子通訊,子對父通訊要用回調函數的方式。 Vue3.0之前沒法檢測到數據屬性的增刪變化,經常使用Vue.prototype.$set和JSON.parse(JSON.stringify)去糾正這一點。將來Vue3.0將用proxy代替
Object.defineProperty
監聽數據變化,proxy將直接監聽對象,而不是監聽屬性,它能夠檢測到數組和對象的增刪變化。
JS開發有三大難點,原型、閉包和做用域。在es6 module的幫助下,原型和閉包的坑已經很少了,剩下的做用域成了最常遇到的坑。
在React當中,給組件添加事件必需要修正函數的執行做用域。像下面這樣,onClick是定義在全局做用域上的,它的this就是undefined。由於js是靜態做用域語言,它做用域是定義時肯定的。在這裏,要拿到React組件實例內部的state,全部bind函數的做用域到組件實例上。
在每個事件函數上,不厭其煩地綁定函數的做用域,這在Vue裏是根本不care的。Vue會在組件實例化的時候,把methods裏的函數做用域都綁定到組件實例上 CSS的做用域問題,也是困擾前端開發者的大問題。命名衝突的className會帶來意想不到的驚喜,採用提高權重的方式,能夠提升選擇器的競爭力,但這會讓項目更加臃腫,CSS管理混亂不堪,維護開發很是麻煩。Vue採用相似shadow DOM的方式對CSS進行封裝,添加了scoped屬性後,CSS只做用在組件內部,組件之間的CSS不會互相影響。
React採用css in js、css module、style-component的方式封裝CSS,都沒有Vue好用。
React的css in js寫法
相比React,Vue和JS這門語言契合度是最高的,它沒有科班化的數據流管理,沒有刀耕火種的JS編寫方式。
Vue的追蹤數據機制、v-model雙向綁定和js/css做用域,都很巧妙的利用JS做爲一門動態語言的優點。這使Vue成爲一門很是容易上手的技術框架,在快節奏、頻繁的迭代的開發需求中佔有一席之地。我在商業產品部一年多一共開發和維護了9個項目,包括1個react、1個angular和7個vue項目。Vue很是容易上手,有些簡單的需求,就讓後端同窗代勞了。
一直以來,都有一個爭議點,Vue適合作小型項目,React適合開發大型項目。之前,Vue飽受詬病的是數據流管理,實際上,如今Vue2和React已經相差不大了,藉助v-model和vuex,Vue甚至比React更勝一籌。將來Vue3會用Typescript寫,構建項目將會更加穩健。
react和vue都在用的組件通訊方式之一,簡約又簡單。
依賴組件父子關係。
以下,子組件實例化過程當中,若是發現父組件訂閱了子組件的事件,就會把訂閱的事件添加到events列表裏,以此容許開發者來發布事件,即$emit事件。
添加訂閱者到event隊列。 若是是祖孫級組件和兄弟級組件,它們之間的通訊就須要不少個emit回調在組件之間傳遞。這種通訊方式會組件耦合性太強,程序穩定性下降。適用於全部組件,不依賴組件之間的嵌套關係。
在EventBus裏,實例化一個Vue實例做爲一個觀察者,全部的組件都做爲訂閱者。
// EventBus.js
import Vue from 'vue';
export default new Vue();
複製代碼
// 添加訂閱者
eventBus.$on('reset-preview', this.closeHandler);
// 發佈通知
eventBus.$emit('preview');
複製代碼
Vue內部實現了on和emit兩個方法,on方法添加訂閱者到隊列裏,emit在事件變化時,發佈通知給訂閱者。
EventBus雖然不依賴組件嵌套關係,可是數據流向是隨意的,對於複雜的業務需求,難以支撐。因此須要一箇中心化的觀察者,觀察數據變化,自上而下組件響應數據變化,自下而上更新數據變化到觀察者中心。
emit回調和eventBus的區別是什麼?
emit回調是強調組件關係,父組件是訂閱者,子組件是發佈者。 eventBus不關心組件關係,eventBus實例化的一個實例是發佈者,組件都是訂閱者。
優勢:
使用vuex須要注意的點
vuex和vue同樣都是經過劫持setter/getter追蹤數據變化的,因此vuex也不能檢測到array和object的增刪。
例如表單型的數據,須要增長字段,向後臺提交。vuex沒法處理屬性增刪,$store.commit到store裏,store裏的數據不會更新。
例如,一個複雜類型的數據,從服務端請求出來存到vuex裏,而後在多個組件之間傳遞,在數據處理結束以後,又提交給服務端。此時,應該清除vuex保存的數據,以便在下一次打開頁面時,vuex裏的數據是乾淨的。
通常,在組件的created生命週期檢查vuex緩存是否存在,沒有緩存,則從新拉數據。在組件生命週期結束前,重置store,清除數據緩存。
什麼狀況下適合用vuex呢?
只有在用React實在解決不了的時候,才用Redux。--------Redux做者
過分使用vuex,將使項目變得臃腫,組件之間耦合度增長。
傳統型,適用於各頁面之間的數據傳遞。對於一些須要粘貼url讓其餘人訪問的需求,須要在router里加上必須參數,而不能在vuex裏。
好比篩選列表頁,媒體流量桶管理頁。這種頁面結構相同,種類又衆多。不能拆分紅多個頁面,但又須要獨立的頁面展現效果,適合把數據保存在route裏。
使用router傳參時,須要注意:
用於嵌套的表單型組件
好比建立父任務時,父任務表單裏同時又能夠添加子任務,子認爲有分別能夠添加不一樣的任務獎勵規則。 好比建立訂單時,能夠添加廣告組、廣告計劃、廣告創意,廣告創意裏能夠添加各種素材。 這些嵌套複雜的表單型組件,比較適合用這個。
修改封閉,擴展開放。
功能組件仍是ui組件?簡化使用。 好比pagnition處理total < 1時,不顯示分頁器 好比篩選列表組件,保留UI部分,把提交按鈕用slot寫進去 功能組件,好比upload組件
儘量減小外部依賴 組件內的功能點,對外界的依賴越少越好。 越簡單越好。 參考設計的最高境界,Kiss規則。
建立axios的實例對ajax的封裝,減小處理回調的代碼量。直接修改axios的攔截器會污染整個工程ajax調用規則。對於屢次import進來的文件,webpack只會打包一次。