是一種只須要將單個頁面加載到服務器之中的web應用程序。當瀏覽器向服務器發出第一個請求時,服務器會返回一個index.html文件,它所需的js,css等會在顯示時統一加載,部分頁面按需加載。url地址變化時不會向服務器在請求頁面,經過路由才實現頁面切換。javascript
優勢:css
缺點:html
在以往開發程序過程當中,界面佈局代碼、界面交互邏輯代碼、業務邏輯代碼三者代碼都是混在一塊兒的。隨着業務需求愈來愈大,代碼愈來愈複雜,不只致使開發困難,更是致使維護代碼更困難,特別是維護別人的代碼。vue
因此就出現MVC模式來解決這個問題,其中M表明Model,專門來處理、存儲數據。V表明View,專門來處理頁面的展現。C表明Controller專門處理業務邏輯。java
用戶操做View,View發送指令到Control,完成業務邏輯處理後,要求Model處理相應的數據,將處理好的數據發送到View,要求View把這些數據展現給用戶。node
固然用戶也能夠直接下發指令到Control,完成對應業務邏輯處理後,要求Model處理相應的數據,將處理好的數據發送到View,要求View把這些數據展現給用戶。webpack
也能夠經過View直接要求Moder處理數據,將處理好的數據發送到View,要求View把這些數據展現給用戶。ios
然而在MVC模式中,Model、Control、View三者相互依賴,修改起來要兼顧其餘二者,仍是很是困難。git
因此又出現了MVP模式來解決這個問題,在MVP模式中P表明Presenter替代原來的Control。github
當用戶操做View,View發送指令到Presenter,完成業務邏輯處理後,要求Model處理相應的數據,將處理好的數據返回到Presenter中,Presenter將數據發送到View中,要求View把這些數據展現給用戶。
MVP模式中,Presenter將View和Model徹底隔離開,Presenter和View相互依賴,Presenter和Model相互依賴,View和Model再也不相互依賴,使代碼耦合下降。
由於Presenter和View相互依賴,這樣Presenter就沒辦法單獨作單元測試,非得等到View作好之後才行。因此對View分割一部分叫作View接口,Presenter只依賴View接口,這樣Presenter不用依賴View就能夠測試了,而且也增長了複用性,只要View實現了View接口部分,Presenter就能夠大發神威。
然而在MVP模式中,由於讓Presenter發送數據到View,讓View展現,仍然須要大量的、煩人的代碼,這實在是一件不舒服的事情。 那麼可不可讓View在Model變化時自動更新。
因此出現了MVVM模式來實現這個設想,其中VM表明ViewModel負責視圖顯示邏輯和監聽視圖變化,M表明Model變成處理業務邏輯和數據。
當用戶操做View時,ViewModel監聽到View的變化,會通知Model中對應的方法進行業務邏輯和數據處理,處理完畢後,ViewModel會監聽到自動讓View作出相應的更新。ViewModel能夠對應多個View,具備很強的複用性。
在Vue項目中。new Vue()就是一個ViewModel,View就是template模板。Model就是Vue的選項如data、methods等。在開發過程咱們只關注View怎麼展現,Model怎麼處理業務邏輯和數據。不要去管處理業務邏輯和數據後怎麼讓View更新,View上有操做,怎麼讓Model處理這個操做,這些統統交給ViewModel來實現,大大下降了開發成本。
Object.defineProperty(obj,prop,descriptor)
方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function() {
console.log('get!');
return temperature;
},
set: function(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
複製代碼
通俗來講是在對目標對象的操做以前提供了攔截,對外界的操做進行過濾和修改某些操做的默認行爲,能夠不直接操做對象自己,而是經過操做對象的代理對象來間接來操做對象。
let proxy = new Proxy(target, handler)
target
是用 Proxy 包裝的目標對象(能夠是任何類型的對象,包括原生數組,函數,甚至另外一個代理);handler
一個對象,其屬性是當執行一個操做時定義代理的行爲的函數,也就是自定義的行爲。handle
能夠爲{}
,可是不能爲null
,不然會報錯
Proxy 目前提供了 13 種可代理操做,比較經常使用的
let obj = {
a : 1,
b : 2
}
let test = new Proxy(obj,{
get : function (target,property) {
return property in target ? target[property] : 0
},
set : function (target,property,value) {
target[property] = 6;
},
has: function (target,prop){
if(prop == 'b'){
target[prop] = 6;
}
return prop in target;
},
})
console.log(test.a); // 1
console.log(test.c); // 0
test.a = 3;
console.log(test.a) // 6
if('b' in test){
console.log(test) // Proxy {a: 6, b: 6}
}
複製代碼
採用的是Mustache的web模板引擎mustache.js
<script type="text/javascript" src="./mustache.js"></script>
<script type="text/javascript">
var data = {
"company": "Apple",
}
var tpl = '<h1>Hello {{company}}</h1>';
var html = Mustache.render(tpl, data);
console.log(html);
</script>
複製代碼
Vue.js 的核心是一個容許採用簡潔的模板語法來聲明式地將數據渲染進 DOM 的系統。
以上是官方原話,從中能夠得知Vue的核心是模板語法和數據渲染。
單向數據流是指數據只能從父級向子級傳遞數據,子級不能改變父級向子級傳遞的數據。
雙向數據流是指數據從父級向子級傳遞數據,子級能夠經過一些手段改變父級向子級傳遞的數據。
好比用v-model
、.sync
來實現雙向數據流。
雙向綁定是指數據模型(Module)和視圖(View)之間的雙向綁定。
其原理是採用數據劫持結合發佈者-訂閱者模式的方式來實現。
Vue中先遍歷data選項中全部的屬性(發佈者)用Object.defineProperty
劫持這些屬性將其轉爲getter/setter。讀取數據時候會觸發getter。修改數據時會觸發setter。
而後給每一個屬性對應new Dep(),Dep是專門收集依賴、刪除依賴、向依賴發送消息的。先讓每一個依賴設置在Dep.target
上,在Dep中建立一個依賴數組,先判斷Dep.target
是否已經在依賴中存在,不存在的話添加到依賴數組中完成依賴收集,隨後將Dep.target
置爲上一個依賴。
組件在掛載過程當中都會new一個Watcher實例。這個實例就是依賴(訂閱者)。Watcher第二參數式一個函數,此函數做用是更新且渲染節點。在首次渲染過程,會自動調用Dep方法來收集依賴,收集完成後組件中每一個數據都綁定上該依賴。當數據變化時就會在seeter中通知對應的依賴進行更新。在更新過程當中要先讀取數據,就會觸發Wacther的第二個函數參數。一觸發就再次再次自動調用Dep方法收集依賴,同時在此函數中運行patch(diff運算)來更新對應的DOM節點,完成了雙向綁定。
而後經過編譯將模板轉成渲染函數render,執行渲染函數render,在其中建立不一樣類型的VNode類,最後整合就能夠獲得一個虛擬DOM(vnode)。
最後經過patch將vnode和oldVnode進行比較後,生成真實DOM。
在初始化的最後,若是檢測到選項有el
屬性,則調用vm.$mount
方法掛載vm
,掛載的目標就是把模板渲染成最終的DOM
。
vm.$options
有render函數。由於在不一樣構建版本上的掛載過程都不同,因此要對Vue原型上的$mount
方法進行函數劫持。
首先建立一個變量mount將Vue原型上的$mount
方法保存到這個變量上。而後Vue原型上的$mount
方法被一個新的方法覆蓋。在這個新方法中調用mount這個原始方法。
經過el屬性進行獲取DOM元素。若是el是字符串,則使用document.querySelector獲取DOM元素並賦值給el。若是獲取不到,則建立一個空的div元素並賦值給el。若是el不是字符串,默認el是DOM元素,不進行處理。
判斷el是否是html元素或body元素,若是是則給出警告退出程序。
由於掛載後續過程當中須要render函數生成vnode,故要判斷$options
選項中是否有render
函數這個屬性,若是有直接調用原始的$mount方法。
若是沒有,則判斷template是否存在。若不存在則將el的outerHTML賦值給template。若存在,若是template是字符串且以#開頭,經過選擇符獲取DOM元素獲取innerHTML賦值給template,若是template已是DOM元素類型直接獲取innerHTML賦值給template。
而後將template編譯成代碼字符串並將代碼字符串轉成render函數,並賦值到vm.$options
的render屬性上。
最後調用原始的$mount
方法。
$mount
方法,先觸發beforeMount
鉤子函數,而後建立一個Watcher實例,在第二參數傳入一個函數vm._update
。該函數是首次渲染和更新渲染做用,參數爲render函數(vnode),若是vm._vnode
不存在則進行首次渲染。
同時vnode中被劫持的數據自動收集依賴。當vnode中被劫持的數據變化時候觸發對應的依賴,從而觸發vm._update
進行更新渲染。
最後觸發mounted
鉤子函數。
JSX就是Javascript和XML結合的一種格式。React發明了JSX,利用HTML語法來建立虛擬DOM。當遇到<
,JSX就當HTML解析,遇到{
就當JavaScript解析。