成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

avalon的ViewModel設(shè)計(jì)

sourcenode / 2029人閱讀

摘要:在等庫(kù)中,開(kāi)頭的屬性方法都是框架自用的。使用或者更新的,就能得到所有訪問(wèn)器屬性的定義對(duì)象,然后合成。至此,內(nèi)部各種概念的關(guān)系圖如下框架設(shè)計(jì)第三版,敬請(qǐng)期待

不是有了Object.defineProperty, Proxy或Reflect,放進(jìn)一個(gè)對(duì)象就new出一個(gè)ViewModel出來(lái)。只能說(shuō),它們是必要條件。我們需要將要監(jiān)聽(tīng)的屬性變成訪問(wèn)器屬性,所有訪問(wèn)器屬性都是共用同一套setter, getter方法。getter里面做依賴收集(不是必須的),setter里做視圖刷新或觸發(fā)該屬性的$watch回調(diào)。在此之前,我們需要完成一套觀察者模式,就是github中常見(jiàn)的EventEmitter庫(kù):

https://github.com/Olical/Eve...

https://github.com/asyncly/Ev...

https://github.com/primus/eve...

但這些庫(kù)的訂閱數(shù)組都是放函數(shù)。我們需要放綁定對(duì)象,需要改造一下,并且改成$watch, $fire接口。

var EventBus = {
    $watch: function (type, callback) {
        var binding = callback
        if (typeof callback === "function") {
            binding = {
                expr: type,
                update: callback
            }
        }
        var bus = this.$events
        var list = bus[type]
        if (!list) {
            list = bus[type] = []
        }
        function unwatch() {
            avalon.Array.remove(list, binding)
            if(!list.length){
               delete bus[type]
            }
        }
        list.push(binding)
        return unwatch
    },
    $fire: function (type, value) {
        var list = this.$events[type]
        if (list && lsit.length) {
            for (var i = 0, obj; obj = list[i++];) {
                obj.update()
            }
        }
    }
}

然后我們?cè)贋樗砑右粋€(gè)$id,用于標(biāo)記這個(gè)VM是作用于頁(yè)面某個(gè)元素上的。

var vm = avalon.define({
    $id: "test",
    aaa: 1,
    bbb: 2
})

{{@aaa}}

我們看avalon.define的一個(gè)簡(jiǎn)單實(shí)現(xiàn):

avalon.define = function(obj) {
    var vm = {}
    var other = {}
    for (var name in obj) {
        if (typeof obj[name] !== "function" && name.charAt(0) !== "$") {
            (function (key, value) {
                function get(){
//在avalon1.4,1.5中這里會(huì)進(jìn)行動(dòng)態(tài)依賴收集,詳見(jiàn)這里
//https://github.com/RubyLouvre/avalon/blob/1.5/src/10%20dependency.js                
                    return get._value
                }
                get._value = value
                Object.defineProperty(obj, key, {
                    set: function (newValue) {
                        if(newValue !== get._value){
                            get._value = newValue
                            if(vm.$hashcode)
                               vm.$fire(key, newValue)
                        }
                        return newValue
                    },
                    get: get
                })
            })(name, obj[name])
        }else{
            other[name] = obj[name]
        }
    }
    for(var name in other){
        vm[name] = other
    }
    vm.$events = {}
    vm.$hashcode = new Date  - Math.random()
    vm.$fire = EventBus.$fire
    vm.$watch = EventBus.$watch
   
    return avalon.vmodels[vm.$id] = vm
}

此外,你可以添加更多以$開(kāi)頭的屬性方法,來(lái)增強(qiáng)它的功能。在avalon, angular等庫(kù)中,$開(kāi)頭的屬性方法都是框架自用的。avalon2的一個(gè)簡(jiǎn)單的vm是藏了許多不可遍歷的$xxx屬性方法:

那么如何將綁定屬性放進(jìn)vm.$events.aaa數(shù)組中呢。這就要靠掃描機(jī)制。從上到下掃描。

avalon.scan = function (el, vm) {
    scanNodes([el], vm)
}
function scanNodes(array, vm) {
    for (var i = 0, el; el = array[i++]; ) {
        switch (el.nodeType) {
            case 1:
                scanTag(el, vm)
                break
            case 3:
                scanText(el, vm)
                break
        }
    }
}

function scanTag(el, vm){
    var id = el.getAttribute("ms-controller")
    if(id && avalon.vmodels[id]){
        var vm2 = avalon.vmodels[id]
        if(vm && vm2 && vm == vm2){
           vm = mergeVM(vm,vm2)
        }else{
           vm = vm2
        }
        el.removeAttribute("ms-controller")
    }
    var bindings = scanAttrs(el,vm)
    for(var i = 0, b; b = bindings[i++];){
        vm.$watch(b.expr, b) //重點(diǎn)
    }
    if(el.children && el.children.length){
        scanNodes(el.children, vm)
    }
}
function scanText(){
    // 用正則檢測(cè)是否有花括號(hào)
    // 有則轉(zhuǎn)換為綁定對(duì)象
    // 并進(jìn)行vm.$watch
}
function scanAttrs(){
    //遍歷el.attributes中所有對(duì)象,看name是否以ms-開(kāi)頭
}

那么如何將綁定屬性放進(jìn)vm.$events.aaa數(shù)組中呢。這就要靠掃描機(jī)制。從上到下掃描。

avalon.scan = function (el, vm) {
    scanNodes([el], vm)
}
function scanNodes(array, vm) {
    for (var i = 0, el; el = array[i++]; ) {
        switch (el.nodeType) {
            case 1:
                scanTag(el, vm)
                break
            case 3:
                scanText(el, vm)
                break
        }
    }
}

function scanTag(el, vm){
    var id = el.getAttribute("ms-controller")
    if(id && avalon.vmodels[id]){
        var vm2 = avalon.vmodels[id]
        if(vm && vm2 && vm == vm2){
           vm = mergeVM(vm,vm2)
        }else{
           vm = vm2
        }
        el.removeAttribute("ms-controller")
    }
    var bindings = scanAttrs(el,vm)
    for(var i = 0, b; b = bindings[i++];){
        vm.$watch(b.expr, b) //重點(diǎn)
    }
    if(el.children && el.children.length){
        scanNodes(el.children, vm)
    }
}
function scanText(){
    // 用正則檢測(cè)是否有花括號(hào)
    // 有則轉(zhuǎn)換為綁定對(duì)象
    // 并進(jìn)行vm.$watch
}
function scanAttrs(){
    //遍歷el.attributes中所有對(duì)象,看name是否以ms-開(kāi)頭
}

里面用到一個(gè)mergeVM方法,其實(shí)也簡(jiǎn)單,就是將兩個(gè)VM合并成一個(gè)新的VM。使用Object.getOwnPropertyDescriptor或者更新的Object.getOwnPropertyDescriptors,就能得到所有訪問(wèn)器屬性的定義對(duì)象,然后合成。如果是古老瀏覽器,我們可以將訪問(wèn)器屬性放到一個(gè)叫$accessors對(duì)象上。

現(xiàn)在我們這個(gè)VM是很簡(jiǎn)單的,它只支持一重屬性,如果屬性的屬性也是對(duì)象呢。這個(gè)我們需要將這define方法遞 歸一下不就行了嗎?!對(duì)于數(shù)組的監(jiān)控,業(yè)界流行的方法是重寫(xiě)數(shù)組的大部分方法,然后再加上一些移除數(shù)組的方法。

至此,avalon內(nèi)部各種概念的關(guān)系圖如下:

from 《javascript框架設(shè)計(jì)》第三版,敬請(qǐng)期待

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87935.html

相關(guān)文章

  • angularViewModel設(shè)計(jì)

    摘要:換言之,的對(duì)應(yīng)的,此外它還有。它們共同構(gòu)成的監(jiān)控系統(tǒng)。和是相輔相成的。兩者一起,構(gòu)成了作用域的核心功能數(shù)據(jù)變化的響應(yīng)。迭代的最大值稱為。框架設(shè)計(jì)第三版,敬請(qǐng)期待 angular的ViewModel有一個(gè)專門的官方術(shù)語(yǔ)叫$scope, 它只是一個(gè)普通構(gòu)造器(Scope)的實(shí)例。換言之,它是一個(gè)普通的JS對(duì)象。為了實(shí)現(xiàn)MVVM框架通常宣傳的那種改變數(shù)據(jù)即改變視圖的魔幻效果,它得裝備上更多更...

    int64 評(píng)論0 收藏0
  • WEB前端面試題整理(二)

    摘要:棧是操作系統(tǒng)在建立某個(gè)進(jìn)程時(shí)或者線程為這個(gè)線程建立的存儲(chǔ)區(qū)域。在具有多線程機(jī)制的操作系統(tǒng)中,處理機(jī)調(diào)度的基本單位不是進(jìn)程而是線程。一個(gè)進(jìn)程可以有多個(gè)線程,而且至少有一個(gè)可執(zhí)行線程。 WEB前端面試題的記錄(二) 1、一次完整的HTTP事務(wù)是怎樣的一個(gè)過(guò)程:基本流程: 域名解析 發(fā)起TCP的3次握手 建立TCP連接后發(fā)起http請(qǐng)求 服務(wù)器端響應(yīng)http請(qǐng)求,瀏覽器得到html代碼 瀏...

    solocoder 評(píng)論0 收藏0
  • 吐槽專用

    摘要:最終選擇了兼容到的,終于使用上框架,雖然它只是個(gè)。沒(méi)有對(duì)比就沒(méi)有傷害本來(lái)想著技術(shù)棧統(tǒng)一,移動(dòng)端也準(zhǔn)備使用。于是,之后對(duì)移動(dòng)端的技術(shù)選型上更加慎重了,最終采用了文檔更漂亮的。易用還真不易用,坑還真多。 吐槽 avalon.js 歷史背景 需求重大調(diào)整,所有業(yè)務(wù)推倒重來(lái)(pc端主要任務(wù)涉及管理后臺(tái)類型的網(wǎng)站); 開(kāi)發(fā)周期很緊,過(guò)年前要上線; 公司pc端業(yè)務(wù)要求兼容到ie8; 2015年前...

    zxhaaa 評(píng)論0 收藏0
  • avalon與masonry結(jié)合

    摘要:相關(guān)組件版本最近,在公司的項(xiàng)目中,要開(kāi)發(fā)一個(gè)使用瀑布流的前臺(tái),衡量了各種解決方案后,還是覺(jué)得最成熟,所以就選用了它。測(cè)試的結(jié)果很令人沮喪,依然沒(méi)有控制節(jié)點(diǎn)的位置,所以應(yīng)該不是這個(gè)問(wèn)題。 相關(guān)組件版本:avalon 1.3.6、masonry 3.1.5 最近,在公司的項(xiàng)目中,要開(kāi)發(fā)一個(gè)使用瀑布流的前臺(tái),衡量了各種解決方案后,還是覺(jué)得masonry最成熟,所以就選用了它。而在之前開(kāi)發(fā)后臺(tái)...

    Kosmos 評(píng)論0 收藏0
  • 一步步編寫(xiě)avalon組件05:樹(shù)組件

    摘要:給人印象中,樹(shù)組件是非常令人畏懼的一個(gè)組件,超級(jí)復(fù)雜,超級(jí)難寫(xiě)。但使用來(lái)做,這卻是級(jí)其簡(jiǎn)單的一件事。換言之,我們用元素作為樹(shù)的節(jié)點(diǎn),那么樹(shù)組件內(nèi)部也需要存在樹(shù)組件,需要形成遞歸結(jié)構(gòu)。的機(jī)制又是出場(chǎng)的時(shí)候了。 給人印象中,樹(shù)組件是非常令人畏懼的一個(gè)組件,超級(jí)復(fù)雜,超級(jí)難寫(xiě)。但使用avalon2來(lái)做,這卻是級(jí)其簡(jiǎn)單的一件事。首先從樣式入做,無(wú)序列表是天然可用的樹(shù)結(jié)構(gòu),幾個(gè)UL元素套在一起,...

    Ocean 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<