zoukankan      html  css  js  c++  java
  • jQuery原理系列-css选择器实现

    jQuery最强大的功能在于它可以通过css选择器查找元素,它的源码中有一半是sizzle css选择器引擎的代码,在html5规范出来之后,增加了document.querySelector和document.querySelectorAll直接查找元素,如果是做移动端开发的,使用jQuery的必要性大大降低。

    用js代码实现css选择器,必然是用正则表达式来识别字符串了,当然浏览器提供的原生api 效率更高,以下代码只做原理性展示,并未优先性能,

    例如

    1)查找id显然是用document.getElementById更高效,浏览器已经做了hash,一次性找到元素不用遍历每个节点。

    2)查找 name用document.getElementsByName更高效,浏览器已经做了一个含有该name的集合,

    3)查找标签名 用document.getElementsByTagName更高效,浏览器已经做了一个含有该tag集合,从这个集合中再查找子集显然可以少遍历很多的元素,至于浏览器是不是在元素创建的时候就更新了缓存的集合就不得而知了,但是从这个集合中判断是不是目标元素的子节点还要用contains也会有性能损耗。

    好了,我们先不考虑用原生api优化选择器的问题,只用纯正则表达式来做一个简单的实现,先用正则判断如果含有#就是id选择器,如果含有点号就是class选择器,如果含有[]就是属性选择器,设定好查找目标后开始遍历子节点,要用递归函数遍历childNodes子节点的id,name,className,getAttribute是否匹配,如果匹配就返回该元素。完整的代码如下:

    html:

    <body>
        <div>
            
            <span id="sp_id">hello,id</span>
            <span class="sp_class">hello,class</span>
             <span name="sp_name" >hello,name</span>
             <b>hello,tag</b>
        </div>
     </body>

    javascript:

    <script type="text/javascript">
         
         
         function find(el, selector) { //查找子节点,用法类似jquery的find函数,仅支持id,class,attr选择器,仅支持返回匹配的第一个元素
            var m = selector.match(/([#.[])([wW]+)/i);
            var type, key,attrName, result;
            if (m) {
                if (m[1] == ".") {
                    type = "class"; key = m[2];
                } else if (m[1] == "#") {
                    type = "id"; key = m[2];
                } if (m[1] == "[") {
                    type = "attr";
                    m = m[2].match(/(w+)=(w+)/i);
                    attrName = m[1];
                    key = m[2];
                }
            } else {
                type = "tag"; key = selector;
            }
            
            function findChild(node) {
                var c;
                for (var i = 0; i < node.childNodes.length; i++) {
                    c = node.childNodes[i];
                    if (type == "class" && c.className == key) {
                        result = c;
                        return;
                    } else if (type == "id" && c.id == key) {
                        result = c;
                        return;
                    } else if (type == "attr" &&  c.getAttribute && c.getAttribute(attrName) == key) {
                        result = c;
                        return;
                    } else if (type == "tag" && c.tagName && c.tagName.toLowerCase() == key) {
                        result = c;
                        return;
                    }
                    findChild(c);
                }
            }
            findChild(el);
            return result;
            
        }
        
        console.log(find(document.body,"#sp_id").innerHTML);
        console.log(find(document.body,".sp_class").innerHTML);
        console.log(find(document.body,"[name=sp_name]").innerHTML);
        console.log(find(document.body,"b").innerHTML);
            
        </script>
  • 相关阅读:
    easyui datagrid 显示 footer
    ie浏览器 vuejs axios Promise 未定义
    react引入富文本编辑器TinyMCE
    react中ant-design组件实现textarea获取光标位置并插入表情图片
    前端日志埋点优化
    iframe父子页面通讯
    HTML5中的audio在react中的使用----语音播放进度条、倍速播放、下载等
    echarts简单入门
    在textarea里实现获取光标位置和选中内容
    lodash数组发现之旅--------The second day
  • 原文地址:https://www.cnblogs.com/windyfancy/p/5180973.html
Copyright © 2011-2022 走看看