avalon是國內最強大的MVVM框架,沒有之一,雖然淘寶KISSY團隊也搞了兩個MVVM框架,但都無疾而終。其餘的MVVM框架都沒幾個。也只有外國人與像我這樣閒的架構師纔有時間鑽研這東西。我很早以前就預言,MVVM是前端的終極解決方案。我以前在盛大無線作盛大通行證就深有體會,一個業務邏輯對應十來個不一樣的界面,分層架構是必不可少的。所以雙向綁定做爲解藥,結合很早就流行的MVC框架,衍生出MVVM這神器。javascript
但這麼牛叉的東西,爲何如今才流行起來呢?要不是谷歌振臂高呼,這個一直縮在flex, wps世界的MVVM就根本不可能在前端冒頭。要知道,微軟也搞了knockout, winjs等MVVM框架。緣由之一,這東西很是難作。早些年,JS沒有後端語言那種監聽對象屬性變更的高級特性,屬性的變更如何同步視圖,這須要很是巧妙的依賴收集機制,綁定(或叫指令)須要把一個編譯器把VM的屬性分離出來,這也不是通常人能搞出來的。加之,前端原本就沒有幾個是專科出來的人,都是半路出家的,寫編譯器與玩轉jQuery不是同一個概念。knockout沒有依賴什麼高級特性,但用戶體驗太差,所以也沒有流行起來。angular的缺點與優勢也很是明顯,幸虧google比較大牌。css
但牆的內外畢竟是兩個世界,這也是avalon存在的理由。avalon最先是模擬knockout爲了解決盛大通行證這樣多界面的東東而研發出來的。爲了避免像knockout那樣彆扭,它是使用IE8的Object.defineProperty劫持用戶對數據的操做,從而實現對視圖的同步。這種設計也比後來的angular的髒檢測優秀許多。但Object.defineProperty是缺陷的,兼容性很差,早期的標準瀏覽器須要用_defineGetter_, _defineSetter_, IE6,IE7,IE8(由於IE8的Object.defineProperty也是有缺陷的)須要用VBScript,爲了弄懂VBScript,我還特地入了一本90塊錢的書。但這不是所有,兼容IE6是很是痛苦的,須要寫大量額外的代碼,所以存在avalon.js與avalon.modern.js兩個版本。前端
avalon.js的兼容性是最好的,支持IE6及很是老的標準瀏覽器。這裏的標準瀏覽器特指W3C陣營中的safari, opera, firefox, chrome。avalon.js在最近幾個月的升級中,還對IE的VML,W3C方的SVG進行各類兼容處理。要知道,就是瀏覽器自身的API,也有各類問題。從這個層面來看,avalon.js的兼容能力比jQuery強多了。而且它能夠與jQuery和平共處,享用其強大的AJAX,動畫, Deferred等功能。加之,avalon如今擁有全職的團隊幫它打造UI庫(OniUI),你們就不用本身去拼湊各類插件了。java
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="avalon.js"> </script> </head> <body> <div>TODO write content</div> </body> </html>
上面就是一個範本,若是想引入avalon.modern.js,就是把上面script標籤的src改一改。jquery
avalon.modern.js以前是叫作avalon.mobile.js,是打算用在移動端的,裏面是用了許多高級API,所以性能比avalon.js高許多。因爲也不算兼容舊式IE(avalon.modern.js是支持IE10及以上的新瀏覽器),許多兼容邏輯也刪掉了,所以體積少了許多,大概少了1000行代碼。git
若是你想作移動端開發呢,這要用到觸屏事件,avalon的倉庫有一個mobile.js,你能夠直接將它的源碼 拷貝到avalon.modern.js裏最後一個花括號的前面,或者這樣引入:github
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="avalon.modern.js"></script> <script src="mobile.js"></script> </head> <body> <div>TODO write content</div> </body> </html>
我建議使用拷貝方式,方便之後咱們經過合併方式,把全部業務邏輯也通通合併成一個文件。chrome
avalon.js自己是自帶加載器,它是符合AMD規範,所以它能夠用requirejs項目的rjs進行合併。若是你們不想用avalon.js的自帶加載器,能夠在緊接着的 script標籤裏將它禁用。後端
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="avalon.modern.js"></script><!--不兼容IE6到8,也不玩移動端就用這個--> <script> avalon.config({ loader: false }) </script> </head> <body> <div>TODO write content</div> </body> </html>
或者直接在源碼裏改,我在公司裏就是直接改源碼:
avalon.ready = function(fn) { if (innerRequire) { innerRequire("ready!", fn) } else if (fireReady === noop) { fn(avalon) } else { readyList.push(fn) } } avalon.config({ loader: false })
或者直接在源碼裏AMD加載器這個模塊刪掉,這樣能夠減小300行代碼
/********************************************************************* * AMD加載器 * **********************************************************************/ var innerRequire var modules = avalon.modules = { "ready!": { exports: avalon }, "avalon": { exports: avalon, state: 2 } } …… …… innerRequire.checkDeps = checkDeps } /********************************************************************* * DOMReady * **********************************************************************/
若是你也用require.js,那麼avalon自帶的DOMReady模塊也能夠省掉。這時,大家能夠引用avalon.shim.js。此JS是基於avalon.js改造而來,你也能夠模仿一下改造avalon.mobile.js。
若是你只支持最新的chrome瀏覽器,好比chrome36,那麼你可使用基於Promise, Object.observe 高級API冶造的avalon.observe.js,它使用全新的編譯器與監聽機制,其性能是目前全部MVVM框架之首!
最後咱們結合require.js, domReady.js,text.js,css.js,jQuery.js作一個簡單的項目吧。
咱們創建一個新項目,結構以下:
其中modules文件是放置不一樣的業務模塊,可能不一樣的模塊由不一樣的人來講,每一個人管好本身的js、html、 css,所以咱們才須要requirejs的text、css插件。vendor是放置第三方JS庫、CSS庫什麼的,main.js爲入口文件,特地與index.html放在醒目的位置。
注意,咱們須要禁用avalon自帶的加載器。
index.html的內容以下:
<!DOCTYPE html> <html> <head> <title>第一個avalon項目</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="vendor/require/require.js" data-main="main.js"></script> <style> .ms-controller{ visibility: hidden; } </style> </head> <body ms-controller="root"> <div>{{header | html}}</div> <div ms-include-src="page"></div> <div>{{footer}}</div> </body> </html>
裏面有許多奇怪的屬性,不要慌,這是avalon的綁定屬性,後面的章節咱們慢慢講。之於requirejs的用法,本身到官網看。
而後是main.js,它大致分爲三大塊:
require.config({//第一塊,配置 baseUrl: '', paths: { jquery: 'vendor/jquery/jquery-2.1.1', avalon: "vendor/avalon/avalon",//必須修改源碼,禁用自帶加載器,或直接刪提AMD加載器模塊 text: 'vendor/require/text', domReady: 'vendor/require/domReady', css: 'vendor/require/css.js' }, priority: ['text', 'css'], shim: { jquery: { exports: "jQuery" }, avalon: { exports: "avalon" } } }); require(['avalon', "domReady!"], function() {//第二塊,添加根VM(處理共用部分) avalon.log("加載avalon完畢,開始構建根VM與加載其餘模塊") avalon.templateCache.empty = " " avalon.define({ $id: "root", header: "這是根模塊,用於放置其餘模塊都共用的東西,好比<b>用戶名</b>什麼的", footer: "頁腳消息", page: "empty" }) avalon.scan(document.body) require(['./modules/aaa/aaa'], function() {//第三塊,加載其餘模塊 avalon.log("加載其餘完畢") }); });
而後每個模塊裏都有其JS文件與模板文件(CSS的引入之後再說)
aaa.html
<div ms-controller="aaa"> <input ms-duplex="username"/>{{username}} </div>
aaa.js
define(["avalon", "text!./aaa.html"], function(avalon, aaa) { avalon.templateCache.aaa = aaa avalon.define({ $id: "aaa", username: "司徒正美" }) avalon.vmodels.root.page = "aaa" })
而後你們運行服務器,就能看到效果(推薦用netBeans,能夠直接右鍵運行)
注意,這不是一個簡單的玩具級helloworld!這是一個工業級的項目的種子原型,之後咱們全部項目均可以根據它進行改造,最後用rjs進行合併壓縮!
最近附上本章節的源碼!