一个简单的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);
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);