淘宝Kissy框架分析【八】
2010-06-20 19:18 BlueDream 阅读(1396) 评论(0) 编辑 收藏 举报这一节将进行KISSY的选择器 selector.js分析.
【程序源码】
J1616.add('selector', function(J, undefined) { var doc = document, DOM = J.DOM, SPACE = ' ', ANY = '*', REG_ID = /^#[\w-]+$/, REG_QUERY = /^(?:#([\w-]+))?\s*([\w-]+|\*)?\.?([\w-]+)?$/; function query(selector, context) { var match, t, ret = [], id, tag, cls, i, len; // #id // tag // .cls // #id tag // #id .cls // tag.cls // #id tag.cls // #id.cls if (J.isString(selector)) { selector = J.trim(selector); // 优先处理selector 为 #id 的情况 if (REG_ID.test(selector)) { t = getElementById(selector.slice(1)); if (t) ret = [t]; // #id无效时 返回空数组 } // selector为其他6种 else if ((match = REG_QUERY.exec(selector))) { id = match[1]; tag = match[2]; cls = match[3]; // $('#id', context[如果前面含有ID选择器,则无需限定环境,直接ID就是最直接的: 否则限定]) if ((context = id ? getElementById(id) : tuneContext(context))) { // #id .cls | #id tag.cls | .cls | tag.cls if (cls) { if (!id || selector.indexOf(SPACE) !== -1) { // 排除 #id.cls ret = getElementsByClassName(cls, tag, context); } // #id.cls else { t = getElementById(id); if (t && DOM.hasClass(t, cls)) { ret = [t]; } } } // #id tag | tag else if (tag) { ret = getElementsByTagName(context, tag); } } } // 分组选择器 else if (selector.indexOf(',') > -1) { if (doc.querySelectorAll) { ret = doc.querySelectorAll(selector); } else { var parts = selector.split(','), r = []; for (i = 0, len = parts.length; i < len; ++i) { r = r.concat(query(parts[i]), context); } ret = uniqueSort(r); } } // 采用外部选择器 else if (J.ExternalSelector) { return J.ExternalSelector(selector, context); } // 依旧不支持, 抛异常 else { error(selector); } } // 传入的Selector是Node else if (selector && selector.nodeType) { ret = [selector]; } // 传入的Selector是NodeList或Array else if (selector && (selector.item || J.isArray(selector))) { ret = selector; } // 传入的 selector是其他值, 返回空数组 // 将NodeList转为普通数组 if (ret.item) { ret = J.makeArray(ret); } return ret; } // 调整 context 为合理值 function tuneContext(context) { if (context === undefined) { context = doc; } else if (J.isString(context) && REG_ID.test(context)) { context = getElementById(context.slice(1)); } else if (context && context.nodeType !== 1 && context.nodeType !== 9) { context = null; } return context; } // query #id function getElementById(id) { return doc.getElementById(id); } // query tag function getElementsByTagName(el, tag) { return el.getElementsByTagName(tag); } // 如果byTagName(el, '*') IE下会连注释节点一起筛选出来 // 下面用特性检测 将getElementsByTagName覆盖 (function() { var div = doc.createElement('div'); div.appendChild(doc.createComment('')); if (div.getElementsByTagName(ANY).length > 0) { getElementsByTagName = function(el, tag) { var ret = el.getElementsByTagName(tag); if (tag === ANY) { var t = [], i = 0, j = 0, node; while ((node = ret[i++])) { // filter if (node.nodeType === 1) { t[j++] = node } } ret = t; } return ret; }; } })(); // query .cls function getElementsByClassName(cls, tag, context) { var els = context.getElementsByClassName(cls), ret = els, i = 0, j = 0, len = els.length, el; if (tag && tag !== ANY) { ret = []; tag = tag.toUpperCase(); for (; i < len; ++i) { el = els[i]; if (el.tagName === tag) { ret[j++] = el } } } return ret; } if (!doc.getElementsByClassName) { // 降级使用 querySelectorAll if (doc.querySelectorAll) { getElementsByClassName = function(cls, tag, context) { return context.querySelectorAll((tag ? tag : '') + '.' + cls); } } // 降级到普通方法 else { getElementsByClassName = function(cls, tag, context) { var els = context.getElementsByTagName(tag || ANY), ret = [], i = 0, j = 0, len = els.length, el, t; cls = SPACE + cls + SPACE; for (; i < len; ++i) { el = els[i]; t = el.className; if (t && (SPACE + t + SPACE).indexOf(cls) > -1) { ret[j++] = el; } } return ret; } } } // 对于分组选择器, 需要进行去重和排序 function uniqueSort(results) { var hasDuplicate = false; // 按照DOM位置排序 results.sort(function(a, b) { var ret = a.sourceIndex - b.sourceIndex; if (ret === 0) { hasDuplicate = true; } return ret; }); if (hasDuplicate) { for (var i = 1; i < results.length; i++) { if (results[i] === results[i - 1]) { results.splice(i--, i); } } } return results; } // throw exception function error(msg) { J.error('Unsupport selector: ' + msg); } J.query = query; J.get = function(selector, context) { return query(selector, context)[0] || null; }; J.mix(DOM, { query: query, get: J.get, filter: function(selector, filter) { var elems = query(selector), match, tag, cls, ret = []; // 默认仅支持最简单的 tag.cls形式 if (J.isString(filter) && (match = REG_QUERY.exec(filter)) && !match[1]) { tag = match[2]; cls = match[3]; filter = function(elem) { return !((tag && elem.tagName !== tag.toUpperCase()) || (cls && !DOM.hasClass(elem, cls))); } } if (J.isFunction(filter)) { ret = J.filter(elems, filter); } // 其他复杂的filter, 采用外部选择器 else if (filter && J.ExternalSelector) { ret = J.ExternalSelector._filter(selector, filter); } // selector为空 或者 不支持 else { error(filter); } return ret; }, test: function(selector, filter) { var elems = query(selector); return DOM.filter(elems, filter).length === elems.length; } }); });