本版本最重要的特性是引進了AMD規范的模塊加載器,亦即原來mass Framework 的並行加載器, 不同之處,它引進了requirejs的xxx!風格的插件機制,比如要延遲到DOM樹建完時觸發,是使用ready!, 要加載css文件是使用css!css_path。
加載器在移動設備或PC的單頁應用不可或缺。根據公司內容的不完全統計,手機等瀏覽器的性能只是PC的十分之一左右,而且測試對象還是公司的有錢同事的手機,什么IP,三星GALAXY。
在過去的一周,整合angular, requirejs遇到各種困難,最后只能到github下載了一個整合好的應用來修改。由於沒有整合的能力,意味着我們的angular就不能隨意升級了。因此深感自帶加載器的重要性。當然加載器一直是微博遇到的一些朋友所熱切盼望的功能。因為要同時同步兩個不是自己能掌控的項目,實在心絞力竭。
現在avalon項目下,除了avalon.js外,還有一個叫avalon.mobile.js的東西,它是avalon.js的優化版,專門使用HTML5時代出現的新屬性構建,不再兼容舊式IE,IE的支持版本為IE10,這就保證移動設備上也能流暢運行。
比如hasClass, addClass, removeClass, toggleClass在avalon.js是這樣實現的
hasClass: function(cls) {
var el = this[0] || {}
if (el.nodeType === 1) {
return !!el.className && (" " + el.className + " ").indexOf(" " + cls + " ") > -1
}
},
addClass: function(cls) {
var node = this[0]
if (cls && typeof cls === "string" && node && node.nodeType === 1) {
if (!node.className) {
node.className = cls
} else {
var a = (node.className + " " + cls).match(rnospaces)
a.sort()
for (var j = a.length - 1; j > 0; --j)
if (a[j] === a[j - 1])
a.splice(j, 1)
node.className = a.join(" ")
}
}
return this
},
removeClass: function(cls) {
var node = this[0]
if (cls && typeof cls > "o" && node && node.nodeType === 1 && node.className) {
var classNames = (cls || "").match(rnospaces) || []
var cl = classNames.length
var set = " " + node.className.match(rnospaces).join(" ") + " "
for (var c = 0; c < cl; c++) {
set = set.replace(" " + classNames[c] + " ", " ")
}
node.className = set.slice(1, set.length - 1)
}
return this
},
toggleClass: function(value, stateVal) {
var state = stateVal,
className, i = 0
var classNames = value.match(rnospaces) || []
var isBool = typeof stateVal === "boolean"
while ((className = classNames[i++])) {
state = isBool ? state : !this.hasClass(className)
this[state ? "addClass" : "removeClass"](className)
}
return this
},
到avalon.mobile則是這樣實現:
hasClass: function(cls) {
var el = this[0] || {}
return el.nodeType === 1 && el.classList.contains(cls)
},
addClass: function(cls) {
var el = this[0]
if (cls && typeof cls === "string" && el && el.nodeType === 1) {
cls.replace(rword, function(c) {
el.classList.add(c)
})
}
return this
},
removeClass: function(cls) {
var node = this[0]
if (cls && typeof cls > "o" && node && node.nodeType === 1 && node.className) {
cls.replace(rword, function(c) {
node.classList.remove(c)
})
}
return this
},
toggleClass: function(value, stateVal) {
var state = stateVal,
className, i = 0
var classNames = value.match(rnospaces) || []
var isBool = typeof stateVal === "boolean"
var node = this[0] || {}, classList
if (classList = node.classList) {
while ((className = classNames[i++])) {
state = isBool ? state : !classList.contains(className)
classList[state ? "add" : "remove"](className)
}
}
return this
},
attr方法在這兩個版本的實現也不一樣,avalon.mobile.js用到了dataset。
data: function(name, value) {
name = "data-" + hyphen(name || "")
switch (arguments.length) {
case 2:
this.attr(name, value)
return this
case 1:
var val = this.attr(name)
return parseData(val)
case 0:
var attrs = this[0].attributes,
ret = {}
for (var i = 0, attr; attr = attrs[i++]; ) {
name = attr.name
if (!name.indexOf("data-")) {
name = camelize(name.slice(5))
ret[name] = parseData(attr.value)
}
}
return ret
}
},
//----------------------------------------------------------
avalon.data = function(name, val) {
var dataset = this[0].dataset;
switch (arguments.length) {
case 2:
dataset[name] = val
return this
case 1:
val = dataset[name]
return parseData(val)
case 0:
var ret = {}
for (var name in dataset) {
ret[name] = parseData(dataset[name])
}
return ret
}
}
avalon.mobile.js甚至嘗試用hidden實現visible綁定
if (typeof DOC.createElement("div").hidden === "boolean") {
bindingHandlers.visible = function(data, vmodels) {
var elem = data.element
watchView(data.value, vmodels, data, function(val) {
elem.hidden = !val
})
}
}
未來的展望,接着眼於下來的0.9版本,將嘗試加強國際化的支持與對數組元素的深層監控, avalon.mobile將嘗試使用webworker, 然后發布正式版1.0!!!!!!!!!!
迷你MVVM框架在github的倉庫https://github.com/RubyLouvre/avalon
