近日在做一些 OA 前端界面,为了更好管理页面代码想写个 js 选择器,写着写着发现很费力,索性在网上找找看,功夫不负有心人, 找到一个 mini css 选择器,且性能不凡:以下代码是压缩后的,仅 2KB
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
近日在做一些 OA 前端界面,为了更好管理页面代码想写个 js 选择器,写着写着发现很费力,索性在网上找找看,功夫不负有心人, 找到一个 mini css 选择器,且性能不凡:以下代码是压缩后的,仅 2KB。
- var $ = (function() {
- var b = /(?:[\w\-\\.#]+)+(?:\[\w+?=([\'"])?(?:\\\1|.)+?\1\])?|\*|>/ig,
- g = /^(?:[\w\-_]+)?\.([\w\-_]+)/,
- f = /^(?:[\w\-_]+)?#([\w\-_]+)/,
- j = /^([\w\*\-_]+)/,
- h = [null, null];
- function d(o, m) {
- m = m || document;
- var k = /^[\w\-_#]+$/.test(o);
- if (!k && m.querySelectorAll) {
- return c(m.querySelectorAll(o))
- }
- if (o.indexOf(",") > -1) {
- var v = o.split(/,/g),
- t = [],
- s = 0,
- r = v.length;
- for (; s < r; ++s) {
- t = t.concat(d(v[s], m))
- }
- return e(t)
- }
- var p = o.match(b),
- n = p.pop(),
- l = (n.match(f) || h)[1],
- u = !l && (n.match(g) || h)[1],
- w = !l && (n.match(j) || h)[1],
- q;
- if (u && !w && m.getElementsByClassName) {
- q = c(m.getElementsByClassName(u))
- } else {
- q = !l && c(m.getElementsByTagName(w || "*"));
- if (u) {
- q = i(q, "className", RegExp("(^|\\s)" + u + "(\\s|$)"))
- }
- if (l) {
- var x = m.getElementById(l);
- return x ? [x] : []
- }
- }
- return p[0] && q[0] ? a(p, q) : q
- }
- function c(o) {
- try {
- return Array.prototype.slice.call(o)
- } catch(n) {
- var l = [],
- m = 0,
- k = o.length;
- for (; m < k; ++m) {
- l[m] = o[m]
- }
- return l
- }
- }
- function a(w, p, n) {
- var q = w.pop();
- if (q === ">") {
- return a(w, p, true)
- }
- var s = [],
- k = -1,
- l = (q.match(f) || h)[1],
- t = !l && (q.match(g) || h)[1],
- v = !l && (q.match(j) || h)[1],
- u = -1,
- m,
- x,
- o;
- v = v && v.toLowerCase();
- while ((m = p[++u])) {
- x = m.parentNode;
- do {
- o = !v || v === "*" || v === x.nodeName.toLowerCase();
- o = o && (!l || x.id === l);
- o = o && (!t || RegExp("(^|\\s)" + t + "(\\s|$)").test(x.className));
- if (n || o) {
- break
- }
- } while (( x = x . parentNode ));
- if (o) {
- s[++k] = m
- }
- }
- return w[0] && s[0] ? a(w, s) : s
- }
- var e = (function() {
- var k = +new Date();
- var l = (function() {
- var m = 1;
- return function(p) {
- var o = p[k],
- n = m++;
- if (!o) {
- p[k] = n;
- return true
- }
- return false
- }
- })();
- return function(m) {
- var s = m.length,
- n = [],
- q = -1,
- o = 0,
- p;
- for (; o < s; ++o) {
- p = m[o];
- if (l(p)) {
- n[++q] = p
- }
- }
- k += 1;
- return n
- }
- })();
- function i(q, k, p) {
- var m = -1,
- o, n = -1,
- l = [];
- while ((o = q[++m])) {
- if (p.test(o[k])) {
- l[++n] = o
- }
- }
- return l
- }
- return d
- })();
把原版也分享下:
- /**
- * "mini" Selector Engine
- * Copyright (c) 2009 James Padolsey
- * -------------------------------------------------------
- * Dual licensed under the MIT and GPL licenses.
- * - http://www.opensource.org/licenses/mit-license.php
- * - http://www.gnu.org/copyleft/gpl.html
- * -------------------------------------------------------
- * Version: 0.01 (BETA)
- */
- var mini = (function() {
- var snack = /(?:[\w\-\\.#]+)+(?:\[\w+?=([\'"])?(?:\\\1|.)+?\1\])?|\*|>/ig,
- exprClassName = /^(?:[\w\-_]+)?\.([\w\-_]+)/,
- exprId = /^(?:[\w\-_]+)?#([\w\-_]+)/,
- exprNodeName = /^([\w\*\-_]+)/,
- na = [null, null];
- function _find(selector, context) {
- /**
- * This is what you call via x() 这是你们所谓的经x
- * Starts everything off... 开始上所有的
- */
- context = context || document;
- var simple = /^[\w\-_#]+$/.test(selector);
- if (!simple && context.querySelectorAll) {
- return realArray(context.querySelectorAll(selector));
- }
- if (selector.indexOf(',') > -1) {
- var split = selector.split(/,/g),
- ret = [],
- sIndex = 0,
- len = split.length;
- for (; sIndex < len; ++sIndex) {
- ret = ret.concat(_find(split[sIndex], context));
- }
- return unique(ret);
- }
- var parts = selector.match(snack),
- part = parts.pop(),
- id = (part.match(exprId) || na)[1],
- className = !id && (part.match(exprClassName) || na)[1],
- nodeName = !id && (part.match(exprNodeName) || na)[1],
- collection;
- if (className && !nodeName && context.getElementsByClassName) {
- collection = realArray(context.getElementsByClassName(className));
- } else {
- collection = !id && realArray(context.getElementsByTagName(nodeName || '*'));
- if (className) {
- collection = filterByAttr(collection, 'className', RegExp('(^|\\s)' + className + '(\\s|$)'));
- }
- if (id) {
- var byId = context.getElementById(id);
- return byId ? [byId] : [];
- }
- }
- return parts[0] && collection[0] ? filterParents(parts, collection) : collection;
- }
- function realArray(c) {
- /**
- * Transforms a node collection into 转换一个节点收藏
- * a real array 一个真正的阵列
- */
- try {
- return Array.prototype.slice.call(c);
- } catch(e) {
- var ret = [],
- i = 0,
- len = c.length;
- for (; i < len; ++i) {
- ret[i] = c[i];
- }
- return ret;
- }
- }
- function filterParents(selectorParts, collection, direct) {
- /**
- * This is where the magic happens. 这就是魔法发生
- * Parents are stepped through (upwards) to 父母们加紧通过向上
- * see if they comply with the selector. 看看他们是否符合选择器
- */
- var parentSelector = selectorParts.pop();
- if (parentSelector === '>') {
- return filterParents(selectorParts, collection, true);
- }
- var ret = [],
- r = -1,
- id = (parentSelector.match(exprId) || na)[1],
- className = !id && (parentSelector.match(exprClassName) || na)[1],
- nodeName = !id && (parentSelector.match(exprNodeName) || na)[1],
- cIndex = -1,
- node,
- parent,
- matches;
- nodeName = nodeName && nodeName.toLowerCase();
- while ((node = collection[++cIndex])) {
- parent = node.parentNode;
- do {
- matches = !nodeName || nodeName === '*' || nodeName === parent.nodeName.toLowerCase();
- matches = matches && (!id || parent.id === id);
- matches = matches && (!className || RegExp('(^|\\s)' + className + '(\\s|$)').test(parent.className));
- if (direct || matches) {
- break;
- }
- } while (( parent = parent . parentNode ));
- if (matches) {
- ret[++r] = node;
- }
- }
- return selectorParts[0] && ret[0] ? filterParents(selectorParts, ret) : ret;
- }
- var unique = (function() {
- var uid = +new Date();
- var data = (function() {
- var n = 1;
- return function(elem) {
- var cacheIndex = elem[uid],
- nextCacheIndex = n++;
- if (!cacheIndex) {
- elem[uid] = nextCacheIndex;
- return true;
- }
- return false;
- };
- })();
- return function(arr) {
- /**
- * Returns a unique array返回一个独特的阵列
- */
- var length = arr.length,
- ret = [],
- r = -1,
- i = 0,
- item;
- for (; i < length; ++i) {
- item = arr[i];
- if (data(item)) {
- ret[++r] = item;
- }
- }
- uid += 1;
- return ret;
- };
- })();
- function filterByAttr(collection, attr, regex) {
- /**
- * Filters a collection by an attribute. 一个收集过滤器一个属性
- */
- var i = -1,
- node, r = -1,
- ret = [];
- while ((node = collection[++i])) {
- if (regex.test(node[attr])) {
- ret[++r] = node;
- }
- }
- return ret;
- }
- return _find;
- })();
以上代码支持 css 风格样式写法包括:
- div
- .example
- body div
- div, p
- div, p, .example
- div p
- div > p
- div.example
- ul .example
- #title
- h1#title
- div #title
- ul.foo > * span
来源: