一个简单的DOM选择器实现

支持ie6+,firefox,chrome等现代浏览器。


  1 /**
  2  * aiQuery
  3  * @author ouxingzhi 
  4  */
  5 void function(window, document, undefined) {
  6     var location = window.location,
  7     Slice = [].slice,
  8     RegTrim = /(?:^\s+|\s+$)/,
  9     RegBlank = /\s+/,
 10     RegOperate = /\s*(?:\s|>|\+|~(?!\=))\s*/i,
 11     RegElement = /^([\w\-]+|\*)?(?:\#([\w\-]+))?(?:\.([\w\-]+))?(?:\[([\w-]+)(?:([~|\^|\$|\*|\|]?=)['"]?([\w-]+)['"]?)?\])?(?:\:([\w-]+(?:\([\w-]+\))?))?$/i;
 12     function AIQuery(Selector, Content) {
 13         Selector = Selector.replace(RegTrim, '');
 14         Content = Content || document;
 15         if (Content.querySelectorAll) {
 16             return Slice.call(Content.querySelectorAll(Selector));
 17         } else {
 18             return querySelectorAll(Selector, Content)
 19         }
 20     }
 21     function querySelectorAll(Selector, Content) {
 22         var Groups = Selector.split(/\s*\,\s*/img),
 23         Results = [];
 24         for (var i = 0,
 25         len = Groups.length; i < len; i++) {
 26             Results = Results.concat(Find(Groups[i], Content))
 27         }
 28         return Results
 29     }
 30     function Find(Selector, Content) {
 31         var Results = [],
 32         atoms = Selector.split(RegOperate),
 33         operates = Selector.match(RegOperate);
 34         operates = operates || [];
 35         for (var i = 0,
 36         len = operates.length; i < len; i++)(operates[i] = /^\s+$/.test(operates[i]) ? ' ': operates[i].replace(RegTrim, ''));
 37         var Results = EachTo(' ', atoms.shift(), operates, atoms, Content);
 38         return Results
 39     }
 40     function EachTo(op, at, operates, atoms, Content) {
 41         var Results = [],
 42         Median = [],
 43         operate,
 44         atom;
 45         if (Content.constructor === Array || 'length' in Content) {
 46             for (var i = 0,
 47             len = Content.length; i < len; i++) {
 48                 Results = Results.concat(EachTo(op, at, operates.slice(0), atoms.slice(0), Content[i]))
 49             }
 50         } else if (Content.constructor === String) {
 51             Content = Find(Content, document);
 52             Results.concat(EachTo(op, at, operates.slice(0), atoms.slice(0), Content[i]))
 53         } else {
 54             Median = GetElementByAny(op, at, Content);
 55             if (Median) {
 56                 if (operates && operates.length && atoms && atoms.length) {
 57                     Results = EachTo(operates.shift(), atoms.shift(), operates, atoms, Median)
 58                 } else {
 59                     Results = Median
 60                 }
 61             }
 62         }
 63         return Results
 64     }
 65     function GetElementByAny(op, at, Content) {
 66         if (typeof OperateFunction[op] !== 'undefined') {
 67             return OperateFunction[op](at, Content)
 68         }
 69     }
 70     var OperateFunction = {
 71         ' ': function(at, Content) {
 72             var einfo = buildElementInfo(at),
 73             preNodes = [];
 74             if (!einfo) return [];
 75             if (einfo.Id) {
 76                 preNodes = document.getElementById(einfo.Id);
 77                 preNodes = preNodes ? [preNodes] : []
 78             } else if (einfo.ClassName && Content.getElementsByClassName) {
 79                 preNodes = Content.getElementsByClassName(einfo.ClassName);
 80                 preNodes = preNodes || []
 81             } else if (einfo.TagName && Content.getElementsByTagName) {
 82                 preNodes = Content.getElementsByTagName(einfo.TagName);
 83                 preNodes = preNodes || []
 84             } else {
 85                 preNodes = Content.getElementsByTagName('*');
 86                 preNodes = preNodes || []
 87             };
 88             return filterNode(einfo, preNodes)
 89         },
 90         '>': function(at, Content) {
 91             var einfo = buildElementInfo(at);
 92             preNodes = Content.childNodes || [];
 93             if (!einfo) return [];
 94             return filterNode(einfo, preNodes)
 95         },
 96         '+': function(at, Content) {
 97             if (Content === document) return [];
 98             var einfo = buildElementInfo(at);
 99             if (!einfo) return [];
100             var results = [],
101             preNodes = (function() {
102                 var nextNode = Content.nextSibling;
103                 while (nextNode && nextNode.nodeType != 1) {
104                     nextNode = nextNode.nextSibling
105                 }
106                 return nextNode
107             })();
108             preNodes = preNodes ? [preNodes] : [];
109             if (preNodes.length) {
110                 results = filterNode(einfo, preNodes)
111             } else {
112                 results = []
113             }
114             return results
115         },
116         '~': function(at, Content) {
117             if (Content === document) return [];
118             var einfo = buildElementInfo(at),
119             preNodes = [];
120             if (!einfo) return [];
121             var sibling = Content.parentNode ? Content.parentNode.childNodes: null;
122             if (sibling) {
123                 for (var i = 0,
124                 len = sibling.length; i < len; i++) if (Content !== sibling[i]) preNodes.push(sibling[i])
125             }
126             return filterNode(einfo, preNodes)
127         }
128     };
129     function buildElementInfo(at) {
130         var Einfo = RegElement.exec(at);
131         if (!Einfo) return;
132         return {
133             TagName: Einfo[1] || undefined,
134             Id: Einfo[2] || undefined,
135             ClassName: Einfo[3] || undefined,
136             AttrName: Einfo[4] || undefined,
137             AttrOper: Einfo[5] || undefined,
138             AttrVal: Einfo[6] || undefined,
139             FakeClass: Einfo[7] || undefined
140         }
141     }
142     function filterNode(Einfo, Nodes) {
143         var results = [],
144             RegClassName,
145             isMatch;
146         if (Einfo.ClassName) RegClassName = new RegExp('\\b' + Einfo.ClassName + '\\b', 'i');
147         for (var i = 0,
148         len = Nodes.length; i < len; i++) {
149             isMatch = true;
150             if (Einfo.TagName !== undefined && Einfo.TagName.toUpperCase() !== Nodes[i].nodeName) isMatch = false;
151             if (Einfo.Id !== undefined && Einfo.Id !== Nodes[i].id) isMatch = false;
152             if (Einfo.ClassName !== undefined && !Nodes[i].className.match(RegClassName)) isMatch = false;
153             isMatch = isMatchAttribute(Einfo, Nodes[i], isMatch);
154             isMatch = isMatchFakeClass(Einfo, Nodes[i], isMatch);
155             if (isMatch) results.push(Nodes[i])
156         }
157         return results
158     }
159     function isMatchAttribute(Einfo, node, isMatch) {
160         if (Einfo.AttrName === undefined && Einfo.AttrOper === undefined && Einfo.AttrVal === undefined) {} else if (Einfo.AttrName !== undefined && Einfo.AttrOper === undefined && Einfo.AttrVal === undefined && node.getAttribute && node.getAttribute(Einfo.AttrName) !== null) {
161             isMatch = true
162         } else if (Einfo.AttrName !== undefined && Einfo.AttrOper !== undefined && Einfo.AttrVal !== undefined && node.getAttribute) {
163             switch (Einfo.AttrOper) {
164             case '=':
165                 isMatch = node.getAttribute(Einfo.AttrName) === Einfo.AttrVal;
166                 break;
167             case '~=':
168                 isMatch = !!(node.getAttribute(Einfo.AttrName) && node.getAttribute(Einfo.AttrName).match(new RegExp('(?:^|\\s+)' + Einfo.AttrVal + '(?:$|\\s+)', 'i')));
169                 break;
170             case '^=':
171                 isMatch = !!(node.getAttribute(Einfo.AttrName) && node.getAttribute(Einfo.AttrName).match(new RegExp('^' + Einfo.AttrVal, 'i')));
172                 break;
173             case '$=':
174                 isMatch = !!(node.getAttribute(Einfo.AttrName) && node.getAttribute(Einfo.AttrName).match(new RegExp(Einfo.AttrVal + '$', 'i')));
175                 break;
176             case '*=':
177                 isMatch = !!(node.getAttribute(Einfo.AttrName) && node.getAttribute(Einfo.AttrName).match(new RegExp(Einfo.AttrVal, 'i')));
178                 break;
179             case '|=':
180                 isMatch = !!(node.getAttribute(Einfo.AttrName) && node.getAttribute(Einfo.AttrName).match(new RegExp('(?:^|\\-)' + Einfo.AttrVal + '(?:$|\\-)', 'i')));
181                 break
182             }
183         }
184         return isMatch
185     }
186     function isMatchFakeClass(Einfo, node, isMatch) {
187         if (Einfo.FakeClass === undefined) {} else {
188             switch (Einfo.FakeClass) {
189             case 'empty':
190                 isMatch = node.innerHTML.replace(RegTrim, '').length == 0;
191                 break;
192             case 'checked':
193                 if (node.nodeName.match(/(?:INPUT|TEXTAREA|BUTTON|SELECT|OPTION)/i)) isMatch = !!node.checked;
194                 break;
195             case 'enabled':
196                 if (node.nodeName.match(/(?:INPUT|TEXTAREA|BUTTON|SELECT|OPTION)/i)) isMatch = !!node.disabled;
197                 break;
198             case 'disabled':
199                 if (node.nodeName.match(/(?:INPUT|TEXTAREA|BUTTON|SELECT|OPTION)/i)) isMatch = !!node.disabled;
200                 break;
201             case 'target':
202                 var hash = location.hash.replace('#', '');
203                 isMatch = hash === node.id || (node.name && hash === node.name);
204                 break
205             }
206         }
207         return isMatch
208     }
209     window['aiQuery'] = AIQuery;
210 } (window, document);
posted @ 2012-11-27 23:05  OD  阅读(851)  评论(0编辑  收藏  举报