前言
最近在做移動端開發,用的是zepto,發現他跟jquery比起來稱之為天坑不足為過,但是由於項目本身原因,以及移動端速度要求的情況下,也只能繼續用下去。
所以在這里做一下匯總
對img標簽空src屬性用attr取值會取得當前url地址的BUG
如下圖,某img標簽有src屬性,但是其src屬性值為空,但是用zepto的attr取src屬性值卻是當前頁面的url地址
BUG原因分析:
//zepto源碼
attr: function(name, value){ var result return (typeof name == 'string' && !(1 in arguments)) ? (!this.length || this[0].nodeType !== 1 ? undefined : (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result ) : this.each(function(idx){ if (this.nodeType !== 1) return if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) }) },
問題在於這個 this[0][name] ,相當於直接取img標簽DOM元素的src屬性,而不是他的attributes屬性里面的值。
在很多情況下元素的DOM屬性和attributes屬性是不一致的,比如臭名昭著的布爾類類型屬性,jquery在這方面做了完善兼容而zepto就沒有,非常簡單粗暴。
臨時解決方案:
編寫一個原生js的獲取屬性的方法
function getAttr(ele, attr) { var e = ele.get(0); var attrs = e.attributes; if (attrs == undefined) { return ""; } else if (attrs[attr] == undefined) { return ""; } else { return attrs[attr].value; } }
判斷當前對象是否是Zepto實例化對象的方法
在jquery中,判斷是不是jquery實例化對象,直接用instanceof就行,即:
var a=$("body"); if(a instanceof jQuery){ //... }
但是在zepto中這樣用是無效的,好在zepto自己提供了一份方法來判斷,即:
var a=$("body"); if(Zepto.zepto.isZ(a)){ //... }
其源碼是:也就是我們直接去判斷instanceof是否zepto.Z即可。
// `$.zepto.Z` swaps out the prototype of the given `dom` array // of nodes with `$.fn` and thus supplying all the Zepto functions // to the array. Note that `__proto__` is not supported on Internet // Explorer. This method can be overriden in plugins. zepto.Z = function(dom, selector) { dom = dom || [] dom.__proto__ = $.fn dom.selector = selector || '' return dom } // `$.zepto.isZ` should return `true` if the given object is a Zepto // collection. This method can be overriden in plugins. zepto.isZ = function(object) { return object instanceof zepto.Z }
使用深度擴展($.extend(true,*,*))后的zepto對象無法使用zepto.isZ來繼續判斷的bug
直接看圖:
原本正常的zepto對象,經過深度擴展后,變成不屬於zepto對象了!!
再看下擴展前后的變化:
obj.a.__proto__;//Object {} obj2.a.__proto__;//[]
根據前面的zepto的源碼可知,原始對象是有原型屬性的,但是經過深度擴展后原型屬性沒有了!!!
這肯定是$.extend內部寫的有問題了:
function extend(target, source, deep) { for (key in source) if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { if (isPlainObject(source[key]) && !isPlainObject(target[key])) target[key] = {} if (isArray(source[key]) && !isArray(target[key])) target[key] = [] extend(target[key], source[key], deep) } else if (source[key] !== undefined) target[key] = source[key] } // Copy all but undefined properties from one or more // objects to the `target` object. $.extend = function(target){ var deep, args = slice.call(arguments, 1) if (typeof target == 'boolean') { deep = target target = args.shift() } args.forEach(function(arg){ extend(target, arg, deep) }) return target }
看完以后發現簡直太敷衍了好么!!
直接就用for in遍歷也就算了,好歹也得判斷下是對象屬性還是原型屬性呀!
當然既然原型沒了,那原型上的方法也就自然全跑到對象上面去了,如此敷衍我也是醉了,如圖:
臨時解決方案:
目前沒想到很好的解決辦法,自己多加一些判斷。如果有誰有更好的方案請一定告訴我。
擴展閱讀
http://chaoskeh.com/blog/some-experience-of-using-zepto.html