JavaScript 散记:Tangram
好吧,为了新框架。学习吧。已经把内部的框架瞄完了。正好正在筹备下一版,趁年末这段时间,学习一下其他的框架,好在下次有机会参与构建的时候用上。Tangram 是百度前不久开源出来的框架,颗粒化比较细,注释也非常详尽,就先瞄瞄吧。下面是一些笔记。
目前这篇文章的状态是:【完结】
1. 文档模式判断
一般很少用。标准模式:document.compatMode === ‘CSS1Compat’。Quirks 模式对应的是 BackCompat。
2. 浏览器判断
采用主流的正则检测。利用正则 test() 执行后会存储的捕获组来匹配到的浏览器版本号,用 parseFloat 来得到最终的大版本号。IE8以上使用 document.documentMode 来获取正确的渲染模式版本号,其他 IE 版本和一般浏览器一样。Maxthon 则使用 try…catch 语句,用浏览器提供的 external.max_version 来获取。
更多的,可以参照 kissy 的 ua-extra.js 。
3. 给数字添加逗号:baidu.number.comma
在 number 扩展这一块,印象比较深的是给数字加逗号的方法。自己也写过,取模,然后匹配。没有考虑小数的情况。Tangram 的做法非常聪明。先截去小数,再用利用正则的 g FLAG,使用 replace 进行配置,最后接上小数部分。
baidu.number.comma = function (source, length) {
if (!length || length < 1) {
length = 3;
}
source = String(source).split(".”);
source[0] = source[0].replace(new RegExp('(\\d)(?=(\\d{' + length + '})+$)', 'ig'), "$1,");
return source.join(".");
};
4. 获取当前元素所属文档
document 的 nodeType === 9。利用短路,获取其实元素的 document。
baidu.dom.getDocument = function (element) {
element = baidu.dom.g(element);
return element.nodeType == 9 ? element : element.ownerDocument || element.document;
}
5. removeClass()
在删除 class 上。Tangram 使用的是将 classname 转化成数组,sort(),然后对比长度。看代码写得这么复杂。就搜索了一下,看是不是像 trim() 一样的某些最佳实践。没搜到什么。想起 mootools,查了一下,写法更简洁。大家都会告诉你,正则其实很慢。然后,大家其实都应该这样,写个测试实例,对比一下性能:http://jsperf.com/removeclass 。在 firefox 下的测试结果是,mootools 的速度是 tangram 的 2 倍。
UPDATE: 2010.1.5 0:18 : -m- 为了删除多个 class,还是 baidu 的快一点。多谢 QiQiBoy 提醒。(其实还真想不出有什么地方需要同时删除 2个以 class 的。)
// © Mootools
removeClass: function(className){
this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
return this;
}
baidu.dom.removeClass = function (element, className) {
element = baidu.dom.g(element);
var oldClasses = element.className.split(/\s+/).sort(),
newClasses = className.split(/\s+/).sort(),
i = oldClasses.length,
j = newClasses.length;
for (; i && j;) {
if (oldClasses[i - 1] == newClasses[j - 1]) {
oldClasses.splice(--i, 1);
} else if (oldClasses[i - 1] < newClasses[j - 1]) {
j--;
} else {
i--;
}
}
element.className = oldClasses.join(' ');
return element;
};
6. Never Ready?
让我们来做一个测试吧。看看这个 Demo 。代码注释说这段代码是来自于 jQuery,-,- 那个 dom load 替代似乎也没执行成功。
if (doc.addEventListener && !opera) {
// Use the handy event callback
doc.addEventListener("DOMContentLoaded", opera ? function () {...
7. 获取当前元素所属 window
其实是代码注释中出现的 Google Closure 注释引起了我的注意。再之,虽然作者相同,这个写法(IE 在前还是标准写法在前?)却似乎和 getDocument 方法不一致。囧,我有洁癖,又在意注释又在意代码风格的。
baidu.dom.getWindow = function (element) {
element = baidu.dom.g(element);
var doc = baidu.dom.getDocument(element);
// 没有考虑版本低于safari2的情况
// @see goog/dom/dom.js#goog.dom.DomHelper.prototype.getWindow
return doc.parentWindow || doc.defaultView || null;
};
8. 获取键值
在 keypress 事件中,按下的键值保存为 keyCode 或者 charCode 值,如果按鍵产生一个值 ‘a’,则 charCode 被设置为 ‘a’ 对应的编码,否则为 keyCode 值。如果你并不关心是 charCode 还是 keyCode,则使用 which 来获取:
baidu.event.getKeyCode = function (event) {
return event.which || event.keyCode;
};
9. 处理 XHR 状态
又是一个注释引起了自己的注意。算是一个 hack 吧。寻找了一下来源,似乎是来自 GWT。Mozilla XHR 删除后仍然被调用,而 IE 可能导致崩溃,使用的 trick 是 setTimeout(fn,0)来处理。自己瞄吧:
/*
* NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
* JavaScript XmlHttpRequest.onreadystatechange handler
* function maybe still be called after it is deleted. The theory is that the
* callback is cached somewhere. Setting it to null or an empty function does
* seem to work properly, though.
*
* On IE, there are two problems: Setting onreadystatechange to null (as
* opposed to an empty function) sometimes throws an exception. With
* particular (rare) versions of jscript.dll, setting onreadystatechange from
* within onreadystatechange causes a crash. Setting it from within a timeout
* fixes this bug (see issue 1610).
*
* End result: *always* set onreadystatechange to an empty function (never to
* null). Never set onreadystatechange from within onreadystatechange (always
* in a setTimeout()).
*/
window.setTimeout(
function () {
// 避免内存泄露
xhr.onreadystatechange = new Function();
if (async) {
xhr = null;
}
}, 0);
10.获取正确 XHR
可能是对于 try…catch 无爱,一直很喜欢 John Resig 在 《精通 JavaScript》中的那一段代码:
// If IE is used, create a wrapper for the XMLHttpRequest object
if (typeof XMLHttpRequest == "undefined") {
XMLHttpRequest = function() {
// Internet Explorer uses an ActiveXObject to create a new
// XMLHttpRequest object
return new ActiveXObject(
// IE 5 uses a different XMLHTTP object from IE 6
navigator.userAgent.indexOf("MSIE 5") >= 0 ? "Microsoft.XMLHTTP": "Msxml2.XMLHTTP");
};
}
// Create the request object
var xml = new XMLHttpRequest();
看起来顺眼多了。当然,try…catch 还是很常用的。比较 Tangram 的这个:
function getXHR() {
if (window.ActiveXObject) {
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {}
}
}
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
}
}
11. clearAttributes()
这个方法是 IE 的私有属性。可以删除一个 HTML 元素里的所有属性。并不删除 ID,样式和仅用以 Script-only 属性。详见 MSDN 的介绍:clearAttributes Method。
12. 处理中文和 HTML 实体字符
在 baidu.string.decodeHTML 中。其实我对 fromCharCode 很陌生,我容易被吓到。但瞄了一下。其实转义就那么点事。-,-
baidu.string.decodeHTML = function (source) {
var str = String(source).replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, "&");
//处理转义的中文和实体字符
return str.replace(/&#([\d]+);/g, function (_0, _1) {
return String.fromCharCode(parseInt(_1, 10));
});
};
13. 软换行
其实在这之前,我不知道。-,- 学习了。不过。正则中 lastMatch 的短属性在 opera 是不运行的(其实所有的都不行,除了 $1~9)。so, Tangram 的代码是需要改一下滴。原代码:
baidu.string.wbr = function (source) {
return String(source).replace(/(?:<[^>]+>)|(?:&#?[0-9a-z]{2,6};)|(.{1})/gi, '$&').replace(/>/g, '>');
};
实例可以看官方 DEMO,Opera 中是不换行滴。
14. 检测是否有相应的属性
用 elem.attributes.getNamedItem(name).specified 返回 True or False。cool 又学习到了。用 hasAttribute 用兼容问题,像 mootool, prototype 都是用 hasAttribute 这种标准 + 特性检测来实现。
baidu.dom.hasAttr = function (element, name) {
element = baidu.g(element);
var attr = element.attributes.getNamedItem(name);
return !!(attr && attr.specified);
};
15. 总结
看了两天多的时间。-,- 好吧,加上今天好像有点感冒的迹像,头晕晕的。但还是挺兴奋的。因为终于看完了,而且今天主管告诉我,从 1 月 1 号起,我的级别 +1 了,真是高兴。来做个总结吧。
- 框架的代码写得很赞,有很多都是 JS 的最佳实践,而且注释很详细,总体感觉就是很赞。
- 代码结构上,没有很多依赖关系,看起来比较不费力。
- 没有动画。但有拖放。
- 库。所有方法都是工具,这可能是大家说她不像一个框架,更像一个库的原因吧。
- 平台上没有问题反馈入口。-,-
其实我是新手,永远的新手。这篇文章只是个人学习的一些记录。说出的疑问(问题)也只是顺便提提。继续学习其他框架吧,好为内部框架的升级出点力。
©2011 幸福收藏夹. 版权所有,转载务必注明. 幸福收藏夹域名已经更新为:sofish.de .
原文来自:幸福收藏夹


