使用avalon ms-ui綁定實現基於組件的開發

來源:互聯網
上載者:User

讓日子過得輕鬆,必須讓代碼不斷往上抽象。avalon的一切就是為這個崇高的目的而迸進——操作資料即操作DOM,遠離DOM進行前端開發。javascript之所以在生命的前十年碌碌無為,都是因為開發人員被這些相容性問題搞怕了。在前十年,人們都是用著那些很底層的原生DOM方法,JS方法進行編程,效率異常低下。隨著Prototype.js, jQuery等庫的出現, 把幾乎所有能封裝都給封裝了, 我們的生活才變得美好起來。但開發企業內部管理系統,卻鮮有聽說用jQuery來搞,大家都愛用開箱即用的EXT UI架構。UI組件無疑是比jQuery這些DOM操作對象強上一截,是更高程度的抽象與封裝。但組件的制定性一般很差,比如說zTree,它就使用外掛程式化來進行擴充。對於目前業界給出的方案,avalon是怎麼做的呢?

首先,像ms-class, ms-hover, ms-on其實是在jQuery的事情,不同的是,它沒有依賴Sizzle這些動則上千行的選取器引擎,而是通過掃描與轉換綁定屬性實現。綁定屬性會轉換一個求值函數,求值函數內部與ViewModel掛鈎,因此能即時同步,外部套著一個DOM操作函數,比如說ms-class,就是根據求值函數的傳回值的真假來調用toggleClass, ms-hover則是通過綁定mouseenter, mouseleave來toggleClass, ms-checked是處理表單元素的checked屬性, ms-visible負責元素的顯示隱藏, ms-if負責將元素移出或插入DOM……短短一個綁定屬性就包含非常高密度的DOM操作,比jQuery更加write less, do more, do simple!這個園子已經有人在用我的avalon,反映都是很不錯的,當然也提了不少改進見意。

其次是組件層面,avalon與angular一樣,提供面向組件的開發,但比angular用法簡單多了。avalon參考了bootstrap這個twitter開發的UI庫,利用data-*屬性進行功能定製(當然,它還有其他形式的配置方式)。並且像bootstrap那樣,只要引入JS,在相關元素上添加ms-ui="組件名",元素節點就會轉換為UI組件,一行代碼也不用你寫。

ms-ui綁定能給我們帶來以下好處:將元素上的綁定屬性減到最少,只需添加ms-ui="組件名",或最多添加data-id="xxx", 保證對HTML最少限度的幹擾。也就是說,美工與前端有了非常明確的分工。而data-id中的值則是對應ViewModel的ID,我們可以通過此ID在avalon.models[ID]中取得ViewModel,從而實現操作資料即操作DOM。

基於組件,使得我們的表現層變成由一個個“積木”堆積而成。Page規則轉向如何協調這些組件的運作,而不是盯著一個個元素節點。不過avalon已經幫你搞定了大部分了。比如說,基本URL遠程請求不同的資源,然後轉換為ViewModel,然後產生某個頁面的地區。還有訊息中心(也叫事件中心),由於ViewModel本來就是用觀察者模式實現的,一個活生生的訊息中心,你不需再造輪子。隨著我們項目的深入,我們積累的各種積木也就越來越多,也就是,我們的工作就越輕鬆,工作效率也就越來越高。

與其他UI庫不一樣的,avalon編寫UI太簡單,太方便了,這得益於它強大的雙向繫結機制。

拿avalon.tabs組件的源碼舉例吧:

(function(avalon) {    var defaults = {        active: 0,        event: "click", //可以使用click, mouseover        collapsible: false,        bottom: false,        removable: false    };    avalon.ui.tabs = function(element, id, vmodels, opts) {        var el, tabsParent, tabs = [], tabpanels = [];        var $element = avalon(element);        //1,設定參數對象options = defaults + opts + $element.data()        var options = avalon.mix({}, defaults);        if (typeof opts === "object") {            avalon.mix(options, opts.$json || opts);        }        avalon.mix(options, $element.data());                $element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");        //2, 清空它內部所有節點,並收集其內容,構建成tabs與tabpanels兩個數組        while (el = element.firstChild) {            if (!tablist && (el.tagName === "UL" || el.tagName === "OL")) {                tabsParent = el;            }            if (el.tagName === "DIV") {                tabpanels.push(el.innerHTML);            }            element.removeChild(el);        }        for (var i = 0; el = tabsParent.children[i++]; ) {            tabs.push(el.innerHTML);        }        //3 設定動態模板        var tablist = '<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header"' +                ' ms-class-ui-corner-all="!bottom"  ms-class-ui-corner-bottom="bottom" ms-each-tab="tabs">' +                '<li class="ui-state-default" ' +                ' ms-class-ui-corner-top="!bottom"' +                ' ms-class-ui-corner-bottom="bottom"' +                ' ms-class-ui-tabs-active="active == $index"' +                ' ms-class-ui-state-active="active == $index"' +                ' ms-' + options.event + '="activate"' +                ' ms-hover="ui-state-hover"' + // float: left; margin: 0.4em 0.2em 0 0; cursor: pointer;這樣jquery ui沒有封裝進去                ' >{{tab|html}}<span class="ui-icon ui-icon-close" style="float: left; margin: 0.4em 0.2em 0 0; cursor: pointer;" ms-if="true" ms-click="remove"></span></li></ul>';        var panels = '<div ms-each-panel="tabpanels" ><div class="ui-tabs-panel ui-widget-content"' +                ' ms-class-ui-corner-bottom="!bottom"' +                ' ms-visible="active == $index" >{{panel|html}}</div></div>';        //4 構建組建的ViewModel        var model = avalon.define(id, function(vm) {            vm.active = options.active;            vm.collapsible = options.collapsible;            vm.tabs = tabs;            vm.tabpanels = tabpanels;            vm.removable = options.removable;            vm.activate = function(e) {                e.preventDefault();                vm.active = this.$scope.$index;            };            vm.remove = function(e) {                e.preventDefault();                var index = this.$scope.$index;                vm.tabs.removeAt(index);                vm.tabpanels.removeAt(index);                avalon.nextTick(function() {                    vm.active = 0;                });            };            vm.bottom = options.bottom;        });                avalon.nextTick(function() {            //5 當這一波掃描過來,再將組建的DOM結構插入DOM樹,並綁定ms-*屬性,然後開始掃描            element.innerHTML = options.bottom ? panels + tablist : tablist + panels;            element.setAttribute("ms-class-ui-tabs-collapsible", "collapsible");            element.setAttribute("ms-class-tabs-bottom", "bottom");            avalon.scan(element, model);        });        return model;    };})(window.avalon);

它基本分為五個步驟,首先怎麼也有5個參數給你傳過來,element為綁定了ms-ui的元素節點,id為data-id的值,沒有架構為你隨機產生一個,opts,這個是ms-ui-optsName="uiName"的一個參數,opts就是架構在眾多ViewModel通過hasOwnerProperty操作分別出來的參數對象。然後第一步,就是設定設定物件,它由defaults + opts + $element.data()組成,制定性應該非常強與靈活。

第二步,將element元素的內部節點進行處理,有時它們也有綁定屬性,但我們不需要立即處理它們——掃描器是從上到下掃描,掃描過後來移除它們,因此阻止它們此時被掃描到——最好方法是將它們移出DOM樹。這個過程可能還要做些操作,隨你喜歡。

第三步,編寫UI的HTML結構。

第四步,定義ViewModel,這時它的ID為我們上面的傳參。

第五步,重新開始掃描,但這時,我們不需要整個頁面都掃描了,只從這個元素開始就行。

有關這個tabs的樣本可到這裡查看。

這裡有兩個重點,一個是掃描。掃描總是從上到下,從左至右,想讓它不被掃描,有三個辦法,ms-skip,這幾乎是永久性的,ms-important,只有ViewModel匹配才進行此地區,最後一個是移出DOM樹。掃描不但是為了轉換綁定,還起到儲存這些關鍵節點的作用(竟然這些節點做了綁定,說明要通過JS處理,而在以前這些都是通過選取器引擎來做,但一般的jQueryer很少自覺將它們緩衝起來,每次用到時都重新選擇,不斷地遍曆DOM樹)。第二個是UI組件的ViewModel的構建,它是我們遠離DOM編程的關鍵。它擁有所有關鍵參數與方法,相當於後端的XML設定檔。當然你也可以什麼也不做,defaults其實已經調試好一切了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.