* `tag .className`
* `tag tag`
* `#id tag.className`
* `.className tag`
* `tag, tag, #id`
* `tag#id.className`
* `.className`
* `span * b`
经过,以上选择语句已经满足了95%以上的需求。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)mini选择器实例代码如下:
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)1.
pAnchors = mini(
);
2.
(
i = 0, l = pAnchors.length; i l; ++i) {
3.
4.
}
下载源码查看,发现源码并不难,至少比jquery简单得多,就想试着分析一下它的源码,练练手,之前我是想分析jquery源码的,但发现实在太难了,超出能力范围了,还是先从简单的代码开始吧。
mini选择器大体上,就是先把选择语句最右边的元素先选出来,再根据左边的父元素层层过滤得到符合整个语句的元素。
例如#a table .red这个语句的选择过程,就是先选出页面上所有class=red的dom元素,再在选出来的元素中判断其父元素是否为table,是则保存,不是则丢弃。这层筛选完后,把结果再进行一次筛选,判断其父元素是否id=a,是则保留,不是则丢弃,最后就筛选出了符合#a table .red的所有dom元素。
其余细节的解析,我用注释的方式加在代码上了。我发现要把分析代码的过程写出来真是很难,代码是看得懂,但就是表达不出来代码的意思。我现在写出来的那些注释,似乎有点乱,估计别人也挺难看懂,不过当练兵吧,我在写之前并没有完全了解mini的原理,写完后就清晰了,看跟写还是有很大区别的,写出来对自己挺有帮助。
有些地方其实我也不是知道得很清晰,可能会有错误存在。代码里我还有一些细节不理解,有疑问的地方我打上了**号,希望高手看到能告知吧~
在可以看到,单独选择一个id占了所有选择语句的一半以上,个人感觉mini没有对id进行单独优化,算是不足吧,并且就算只选择一个id,mini(#id)返回的也是一个数组,很不方便,实用性不强。
源码解析:
001.
002.
003.
004.
mini = (
(){
005.
006.
snack = /(?:[w-\.
007.
exprClassName = /^(?:[w-_]+)?.([w-_]+)/,
008.
exprId = /^(?:[w-_]+)?
009.
exprNodeName = /^([w*-_]+)/,
010.
011.
na = [
,
];
012.
013.
_find(selector, context) {
014.
015.
016.
context = context || document;
017.
018.
019.
simple = /^[w-_
020.
021.
(!simple && context.querySelectorAll) {
022.
023.
024.
realArray(context.querySelectorAll(selector));
025.
}
026.
027.
028.
029.
030.
(selector.indexOf(
) -1) {
031.
split = selector.split(/,/g), ret = [], sIndex = 0, len = split.length;
032.
(; sIndex len; ++sIndex) {
033.
ret = ret.concat( _find(split[sIndex], context) );
034.
}
035.
unique(ret);
036.
}
037.
038.
039.
040.
parts = selector.match(snack),
041.
042.
043.
044.
part = parts.pop(),
045.
046.
047.
id = (part.match(exprId) || na)[1],
048.
049.
050.
051.
052.
className = !id && (part.match(exprClassName) || na)[1],
053.
nodeName = !id && (part.match(exprNodeName) || na)[1],
054.
055.
056.
collection;
057.
058.
059.
(className && !nodeName && context.getElementsByClassName) {
060.
061.
collection = realArray(context.getElementsByClassName(className));
062.
063.
}
{
064.
065.
066.
067.
collection = !id && realArray(context.getElementsByTagName(nodeName ||
));
068.
069.
070.
(className) {
071.
collection = filterByAttr(collection,
, RegExp(
+ className +
));
072.
}
073.
074.
075.
076.
(id) {
077.
byId = context.getElementById(id);
078.
byId?[byId]:[];
079.
}
080.
}
081.
082.
083.
084.
085.
parts[0] && collection[0] ? filterParents(parts, collection) : collection;
086.
087.
}
088.
089.
realArray(c) {
090.
091.
/**
092.
* 把元素集合转换成数组
093.
*/
094.
095.
{
096.
097.
098.
Array.prototype.slice.call(c);
099.
}
(e) {
100.
101.
102.
ret = [], i = 0, len = c.length;
103.
(; i len; ++i) {
104.
ret[i] = c[i];
105.
}
106.
ret;
107.
}
108.
109.
}
110.
111.
filterParents(selectorParts, collection, direct) {
112.
113.
114.
parentSelector = selectorParts.pop();
115.
116.
117.
118.
(parentSelector ===
) {
119.
filterParents(selectorParts, collection,
);
120.
}
121.
122.
123.
ret = [],
124.
r = -1,
125.
126.
127.
id = (parentSelector.match(exprId) || na)[1],
128.
className = !id && (parentSelector.match(exprClassName) || na)[1],
129.
nodeName = !id && (parentSelector.match(exprNodeName) || na)[1],
130.
131.
132.
cIndex = -1,
133.
node, parent,
134.
matches;
135.
136.
137.
nodeName = nodeName && nodeName.toLowerCase();
138.
139.
140.
( (node = collection[++cIndex]) ) {
141.
142.
parent = node.parentNode;
143.
144.
{
145.
146.
147.
matches = !nodeName || nodeName ===
|| nodeName === parent.nodeName.toLowerCase();
148.
149.
matches = matches && (!id || parent.id === id);
150.
151.
152.
matches = matches && (!className || RegExp(
+ className +
).test(parent.className));
153.
154.
155.
156.
(direct || matches) {
; }
157.
158.
}
( (parent = parent.parentNode) );
159.
160.
161.
162.
(matches) {
163.
ret[++r] = node;
164.
}
165.
}
166.
167.
168.
selectorParts[0] && ret[0] ? filterParents(selectorParts, ret) : ret;
169.
170.
}
171.
172.
unique = (
(){
173.
174.
175.
uid = +
Date();
176.
177.
data = (
(){
178.
179.
n = 1;
180.
181.
(elem) {
182.
183.
184.
185.
186.
cacheIndex = elem[uid],
187.
nextCacheIndex = n++;
188.
189.
(!cacheIndex) {
190.
elem[uid] = nextCacheIndex;
191.
;
192.
}
193.
194.
;
195.
196.
};
197.
198.
})();
199.
200.
(arr) {
201.
202.
length = arr.length,
203.
ret = [],
204.
r = -1,
205.
i = 0,
206.
item;
207.
208.
209.
(; i length; ++i) {
210.
item = arr[i];
211.
(data(item)) {
212.
ret[++r] = item;
213.
}
214.
}
215.
216.
217.
uid += 1;
218.
219.
220.
ret;
221.
222.
};
223.
224.
})();
225.
226.
filterByAttr(collection, attr, regex) {
227.
228.
/**
229.
* 通过属性名筛选元素
230.
*/
231.
232.
i = -1, node, r = -1, ret = [];
233.
234.
( (node = collection[++i]) ) {
235.
236.
237.
(regex.test(node[attr])) {
238.
ret[++r] = node;
239.
}
240.
}
241.
242.
ret;
243.
}
244.
245.
246.
_find;
247.
248.
})();