在网上发现一个JavaScript小型选择器,其介绍在已经说得挺清楚了,就不再罗嗦了。简单来说,mini选择器只支持以下选择语句:
* `tag`
* `tag .className`
* `tag tag`
* `#id tag.className`
* `.className tag`
* `tag, tag, #id`
* `tag#id.className`
* `.className`
* `span * b`
经过,以上选择语句已经满足了95%以上的需求。
mini选择器实例代码如下:
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的原理,写完后就清晰了,看跟写还是有很大区别的,写出来对自己挺有帮助。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)有些地方其实我也不是知道得很清晰,可能会有错误存在。代码里我还有一些细节不理解,有疑问的地方我打上了**号,希望高手看到能告知吧~
在可以看到,单独选择一个id占了所有选择语句的一半以上,个人感觉mini没有对id进行单独优化,算是不足吧,并且就算只选择一个id,mini(#id)返回的也是一个数组,很不方便,实用性不强。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)源码解析:
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.})(); 

