`
openxtiger
  • 浏览: 151248 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

[Js++开发历程] 巧妙使用querySelector实现类似JQuery.is函数

    博客分类:
  • Js++
 
阅读更多

 

  is() 根据选择器、元素或 jQuery 对象来检测匹配元素集合,如果这些元素中至少有一个元素匹配给定的参数,则返回 true。

它产用是Sizzle技术。

  那我们如何使用querySelector模仿呢?

  由于querySelector只能查找dom以下的DOM,所以我考虑到将采用dom的父dom来使用querySelector

  由于querySelector无法查找精确子DOM(它将会查找其所有的子孙DOM),而且,要查找的dom可能会有很多兄弟

  所以要重新定位到要查找的dom就有困难了,这时,我又想到id,由于在HTML中我们会规范,界面中需要唯一的ID

  有了以上的条件,JQuery.is的模拟就有可能了,直接上代码

第一种方案:

 

var tagTokenRe = /^(#)?([\w\\-\\*]+)/;

function is(dom, selector) {
    var tokenMatch = selector.match(tagTokenRe);
    if (tokenMatch) {
        if (tokenMatch[1] == "#") {
            if (dom.id != tokenMatch[2]) {
                return false;
            }
        } else {
            if (dom.tagName.toLowerCase() != tokenMatch[2].toLowerCase()) {
                return false;
            }
        }
        selector = selector.replace(tokenMatch[0], "");
        if (!selector) return true;
    }
    var pdom;
    if (dom && (pdom = dom['parentNode'])) {
        var id = dom.id;
        if (!id) {
            dom.id = id = "_J" + ++$.guid;
        }
        selector = '#' + id + selector;
        var ret = pdom.querySelector(selector);

        return ret !== null;
    }
    return false;
}

 以上缺点是要保障子dom的兄弟不能有相同的ID

 为了保障,可以将

 

var id = dom.id;
        if (!id) {
            dom.id = id = "_J" + ++$.guid;
        }
        selector = '#' + id + selector;
        var ret = pdom.querySelector(selector);

改为第二种方案

 

var id = dom.id;
       dom.id = '_JIS_'
        selector = '#' + dom.id + selector;
        var ret = pdom.querySelector(selector);
dom.id = id?id:null;

这样就可以保证ID的唯一性,但会降低性能。

 

 

 

 

第三种方案,采用存JS实现的如下:

 

var modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
            tagTokenRe = /^(#)?([\w\\-\\*]+)/,
            tplRe = /\{(\d+)\}/g,
            cache = {};

        var matchers = [
            {re: /^\.([\w-]+)/, select: 'n = byClassName(n, " {1} ");if(n.length==0) return false;\n'},
            {re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/, select: 'n = byPseudo(n, "{1}", "{2}");if(n.length==0)return false;\n'},
            {re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/, select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");if(n.length==0) return false;\n'},
            {re: /^#([\w-]+)/, select: 'n = byId(n, "{1}");if(n.length==0) return false;\n'}
        ];
        var operators = {
            "=": function (a, v) {
                return a == v;
            }, "!=": function (a, v) {
                return a != v;
            }, "^=": function (a, v) {
                return a && a.substr(0, v.length) == v;
            }, "$=": function (a, v) {
                return a && a.substr(a.length - v.length) == v;
            }, "*=": function (a, v) {
                return a && a.indexOf(v) !== -1;
            }, "%=": function (a, v) {
                return (a % v) == 0;
            }, "|=": function (a, v) {
                return a && (a == v || a.substr(0, v.length + 1) == v + '-');
            }, "~=": function (a, v) {
                return a && (' ' + a + ' ').indexOf(' ' + v + ' ') != -1;
            }
        };

        var pseudos = {
            "contains": function (c, v) {
                var r = [], ri = -1;
                for (var i = 0, ci; ci = c[i]; i++) {
                    if ((ci.textContent || ci.innerText || '').indexOf(v) != -1) {
                        r[++ri] = ci;
                    }
                }
                return r;
            },
            "checked": function (c) {
                var r = [], ri = -1;
                for (var i = 0, ci; ci = c[i]; i++) {
                    if (ci.checked == true) {
                        r[++ri] = ci;
                    }
                }
                return r;
            }
        };

        function compile(path) {
            // setup fn preamble
            var fn = ["var f = function(root){\nvar n = root || document;\n"],
                lastPath,
                matchersLn = matchers.length,
                modeMatch;


            // strip leading slashes
            while (path.substr(0, 1) == "/") {
                path = path.substr(1);
            }

            while (path && lastPath != path) {
                lastPath = path;
                var tokenMatch = path.match(tagTokenRe);
                if (tokenMatch) {
                    if (tokenMatch[1] == "#") {
                        fn[fn.length] = 'n = byId(n, "' + tokenMatch[2] + '");if(n.length==0) return false;\n';
                    } else {
                        fn[fn.length] = 'n = byTag(n, "' + tokenMatch[2] + '");if(n.length==0) return false;\n';
                    }
                    path = path.replace(tokenMatch[0], "");
                }
                while (!(modeMatch = path.match(modeRe))) {
                    var matched = false;
                    for (var j = 0; j < matchersLn; j++) {
                        var t = matchers[j];
                        var m = path.match(t.re);
                        if (m) {
                            fn[fn.length] = t.select.replace(tplRe, function (x, i) {
                                return m[i];
                            });
                            path = path.replace(m[0], "");
                            matched = true;
                            break;
                        }
                    }
                    // prevent infinite loop on bad selector
                    if (!matched) {
                        throw 'Error parsing selector, parsing failed at "' + path + '"';
                    }
                }
            }
            // close fn out
            fn[fn.length] = "\nreturn n.length>0;\n}";
            // eval fn and return it
            eval(fn.join(""));
            return f;
        }

        function byId(cs, id) {
            if (cs.tagName || cs == document) {
                cs = [cs];
            }
            if (!id) {
                return cs;
            }
            var result = [], ri = -1;
            for (var i = 0, ci; ci = cs[i]; i++) {
                if (ci && ci.id == id) {
                    result[++ri] = ci;
                    return result;
                }
            }
            return result;
        }

        function byTag(cs, tagName) {
            if (cs.tagName || cs == document) {
                cs = [cs];
            }
            if (!tagName) {
                return cs;
            }
            var result = [];
            tagName = tagName.toLowerCase();
            for (var i = 0, ci; ci = cs[i]; i++) {
                if (ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName) {
                    result.push(ci);
                }
            }
            return result;
        }

        function byAttribute(cs, attr, value, op, custom) {
            var result = [],
                ri = -1,
                fn = operators[op],
                a,
                innerHTML;
            for (var i = 0, ci; ci = cs[i]; i++) {
                // skip non-element nodes.
                if (ci.nodeType != 1) {
                    continue;
                }

                innerHTML = ci.innerHTML;
                // we only need to change the property names if we're dealing with html nodes, not XML

                if (innerHTML !== null && innerHTML !== undefined) {
                    if (attr == "class" || attr == "className") {
                        a = ci.className;
                    } else if (attr == "for") {
                        a = ci.htmlFor;
                    } else if (attr == "href") {
                        a = ci.getAttribute("href", 2);
                    } else {
                        a = ci.getAttribute(attr);
                    }
                } else {
                    a = ci.getAttribute(attr);
                }
                if ((fn && fn(a, value)) || (!fn && a)) {
                    result[++ri] = ci;
                }
            }
            return result;
        }

        function byClassName(nodeSet, cls) {
            if (!cls) {
                return nodeSet;
            }
            var result = [], ri = -1;
            for (var i = 0, ci; ci = nodeSet[i]; i++) {
                if ((' ' + ci.className + ' ').indexOf(cls) != -1) {
                    result[++ri] = ci;
                }
            }
            return result;
        }

        function byPseudo(cs, name, value) {
            if (cs.tagName || cs == document) {
                cs = [cs];
            }
            return pseudos[name](cs, value);
        }

经过1000000的测试:

第一种方案需要9849ms,第二种方案需要13124ms,第三种方法需要9729ms。

 

 

 

 

1
3
分享到:
评论

相关推荐

    JavaScript+jQuery程序设计 源码

    通过分析和实践这个"JavaScript+jQuery程序设计 源码",学习者不仅能巩固JavaScript和jQuery的基础知识,还能提升实际项目开发经验,尤其是处理网页交互和动态效果的能力。同时,这也将有助于理解和应用更多高级特性...

    Web前端开发技术-认识JQuery.pptx

    jQuery是一个广泛应用于Web前端开发的JavaScript库,它的主要目标是简化JavaScript的使用,让开发者可以用更少的代码实现更多的功能。jQuery的核心理念是"write Less, Do More",它通过封装常见的JavaScript任务,如...

    精通JavaScript+jquery_02-10实例

    在本资源中,“精通JavaScript+jQuery_02-10实例”涵盖了JavaScript和jQuery的多个核心章节,旨在帮助用户深入理解和熟练运用这两种强大的Web开发工具。JavaScript是一种广泛应用于客户端浏览器的脚本语言,而jQuery...

    JavaScript+jQuery程序设计(某课版)ppt

    本课程的"JavaScript+jQuery程序设计(某课版)ppt"旨在为教师提供全面的教学资源,帮助他们深入讲解这两种语言的核心概念和技术。 JavaScript是一种广泛使用的客户端脚本语言,它允许在用户浏览器上运行代码,从而...

    web前端 html+css+js+jquery 网易云音乐官网模仿

    例如,使用`addEventListener`绑定事件处理函数,`document.querySelector`或`document.getElementById`选取特定元素,`AJAX`或`fetch`实现异步数据加载。 **jQuery** jQuery是一个流行的JavaScript库,简化了DOM...

    Mason, Mason.js for creating a perfect grid with jQuery..zip

    《使用Mason.js构建完美的jQuery网格布局》 在网页设计中,网格系统是不可或缺的一部分,它可以帮助我们创建出美观、响应式的布局。Mason.js就是这样一款强大的JavaScript库,结合jQuery,能够帮助开发者轻松实现...

    Html+Css+js+jquery实现简单页面的登录

    在网页开发中,创建一个简单的登录页面是基础且重要的一步,它涉及到HTML、CSS和JavaScript(通常配合jQuery库)这三种主要技术的协同工作。在这个过程中,HTML负责构建页面结构,CSS用于美化页面样式,而JavaScript...

    input输入框获取js点击文字内容无jquery.zip

    本项目“input输入框获取js点击文字内容无jquery.zip”似乎关注的是如何使用JavaScript(而非jQuery)来获取`&lt;input&gt;`输入框内用户点击的文字内容。这涉及到JavaScript的事件处理和DOM操作,下面我们将详细探讨这些...

    原生的强大DOM选择器querySelector.pdf

    如果你需要在这些老版本的IE浏览器中使用类似的功能,可能需要借助于jQuery或其他库提供的方法。 **性能比较** 虽然querySelector和querySelectorAll非常实用,但它们并非在所有情况下都比其他DOM操作方法快。在...

    原生的强大DOM选择器querySelector介绍.docx

    querySelector 的优点是使用简洁,使用方式与 CSS 选择器完全一样,对于前端开发人员来说,难度几乎为零。它可以用于查找单个元素或多个元素,返回匹配到的第一个元素或包含匹配到的元素的数组。 querySelector 的...

    js querySelector() 使用方法

    `querySelector()` 是JavaScript中用于选择DOM元素的强大方法,它基于CSS选择器来定位页面上的特定元素。这个方法在处理单个元素时非常有用,因为`querySelector()`只会返回匹配选择器的第一个元素,而不是像`...

    jquery,js简单实现类似Angular.js双向绑定

    本文介绍了一种使用jQuery和JavaScript实现类似Angular.js的双向数据绑定的方法。所谓双向数据绑定,是指在用户界面上展示数据模型的变化,同时当用户界面发生变化时,数据模型也会自动更新。在Angular.js这样的现代...

    autocomplete——js,css文件+ 例子

    这个压缩包包含的资源是实现这一功能的JavaScript和CSS文件,以及相关的示例。接下来,我们将详细探讨JavaScript、CSS以及它们在自动补全功能中的应用。 **JavaScript** JavaScript 是一种广泛用于网页动态效果和...

    jQuery和JavaScript使用小案例

    在JavaScript中,我们可以实现与jQuery类似但更底层的功能。例如,使用原生JavaScript获取元素: ```javascript var element = document.getElementById("elementId"); ``` 并添加事件监听器: ```javascript ...

    jQuery的鼠标左右键自定义菜单代码.zip

    var onClick = function(e) { ...document.querySelector('a.context').addEventListener('contextmenu', onClick) document.querySelector('a.touchend').addEventListener('touchend', onClick) })

    Jquery、JS开发帮助文档

    在IT行业中,JavaScript(简称JS)和jQuery是前端开发领域不可或缺的工具,而CSS则用于构建优雅的页面样式。这份“Jquery、JS开发帮助文档”涵盖了这些关键领域的详细讲解,对于开发者来说是一份非常宝贵的资源。...

    轮播图效果(原生js+jquery+bootstrap三种)

    本资源提供了三种不同的轮播图实现方法:原生JavaScript、jQuery和Bootstrap。下面将详细阐述这三种方法的核心知识点。 1. **原生JavaScript实现**: 原生JavaScript实现轮播图需要掌握的基础概念包括DOM操作、...

    利用JS+CSS实现滚动表格数据展示

    下面将详细介绍如何通过JavaScript(JS)和层叠样式表(CSS)来实现这一功能。 首先,我们需要创建一个基本的HTML结构,包含一个`&lt;table&gt;`元素,用于展示数据。表格通常由`&lt;thead&gt;`(表头)、`&lt;tbody&gt;`(表格主体)...

    Javascript + jQuery

    JavaScript 和 jQuery 是两种在网页开发中广泛使用的编程技术。JavaScript 是一种轻量级的脚本语言,主要用于浏览器端,使得网页具有动态交互性。而 jQuery 是一个 JavaScript 库,它简化了 JavaScript 的语法,提供...

    JavaScript实现类似QQ式的菜单

    在这个项目中,我们讨论的是如何使用JavaScript实现一个类似QQ式的动态菜单。这种菜单通常具有响应迅速、交互性强的特点,能够提供类似于即时通讯软件QQ中的下拉菜单效果。 首先,创建这样的动态菜单需要理解...

Global site tag (gtag.js) - Google Analytics