zoukankan      html  css  js  c++  java
  • 仿照jQuery写一个关于选择器的框架(带了注释,请多多指教~)

    var select = (function () {
      //这是一个异常与捕获的代码,它表示的意思是:如果push方法出现了错误那么就需要重写push方法
      try {
        //这边是自己模拟一个场景,来使用系统的push方法,如果可以实现的话就证明系统支持push方法
        //这种方法是系统能力检测中的方法功能检测
        var div = document.createElement( 'div' );
        div.innerHTML = '<p></p>';
        var arr = [];
        push.apply( arr, div.getElementsByTagName( 'p' ));
      } catch ( e ) {
        //这边是当try里面的push方法不执行的时候,会进入这里面
        //在这里面将push重新定义了一下,将其变为一个对象,这个对象里面有一个push方法
        var push = {
          //将apply变成了push对象里面的一个方法
          apply: function ( array1, array2 ) {
            for ( var i = 0; i < array2.length; i++ ) {
            //注意这边的赋值
            array1[ array1.length++ ] = array2[ i ];
            }
          }
        };
      }
      // 正则表达式
      //这句正则表达式是为了匹配系统中是否有自带的方法
      var rnative = /{s*[native/;
      var rtrim = /^s+|s+$/g;
      //这个是为了匹配出 Id 类名 通配符 标签名
      //              1        2    3    4
      var rbaseselector = /^(?:#([w-]+)|.([w-]+)|(*)|(w+))$/;
      // 基本函数, support 对象, 验证 qsa 与 byclass
      var support = {};
      //基本函数里面的一个属性,实质上是为了看一下系统中是否有该方法(使用正则来判断)
      support.qsa = rnative.test( document.querySelectorAll + '' );
      //同上
      support.getElementsByClassName = rnative.test( document.getElementsByClassName + '' );
      support.trim = rnative.test( String.prototype.trim + '' );
      support.indexOf = rnative.test( Array.prototype.indexOf + '' );
      // 基本方法
      //封装了getElementsByClassName函数,这是为了解决兼容问题
      //传入两个参数,一个是className,另一个是node-->这个node指的是从页面上的node元素开始查找这个className
      function getByClassName ( className, node ) {
        //如果没有传入node的话就给它一个默认值:document
        node = node || document;
        //声明一些变量
        var allElem, res = [], i;
        //首先做判断,如果系统有这个方法会使用系统的
        if ( support.getElementsByClassName ) {
          //直接使用定义的push方法
          return push.apply(res,node.getElementsByClassName( className ));
        } else {
          allElem = node.getElementsByTagName( '*' );
          for ( i = 0; i < allElem.length; i++ ) {
          if ( allElem[ i ].className === className ) {
            res.push( allElem[ i ] );
            }
          }
        return res;
        }
      }
      // 自定义实现 trim 方法,该方法是将字符串中的指定的东西去掉
      var myTrim = function ( str ) {
        // 表示两端去空格, 然后返回去除空格的结果
        if ( support.trim ) {
          return str.trim();
        } else {
          // 自定义实现
          //这边是将rtrim转换成空字符串,即将空格去掉了
          return str.replace( rtrim, '' );
          }
        }
        //这边封装的是indexOf方法,传入三个参数,数组,要搜索的东西,要搜索的东西在数组里面的开始索引(从第几个开始找)
        var myIndexOf = function ( array, search, startIndex ) {
        //首先将索引赋值,如果传入了索引,那么就让开始的索引等于它,如果没有传入那么就让它从零开始找
        startIndex = startIndex || 0;
        //这边还是先判断系统有没有这种方法
        if ( support.indexOf ) {
        //这里表示系统有这种方法,那么就直接使用就OK了,将结果返回
          return array.indexOf( search, startIndex );
        } else {
          //如果没有的话,我们就自己动手封装一个
          //对这个数组进行一个遍历,遍历的初始值就是从startIndex开始
          for ( var i = startIndex; i < array.length; i++ ) {
          //判断一下,如果数组里面有值与要查询的值相等,那么就返回这个索引值
          if ( array[ i ] === search ) {
            return i;
          }
        }
        //当遍历完成之后,如果还是没有找到的话,就返回-1
        return -1;
       }
      }
      //封装一个去重的函数,传入的参数是一个数组
      var unique = function ( array ) {
        //声明一个空数组,用于接收去重之后的元素
        var resArray = [], i = 0;
        //对传入的数组进行一个遍历
        for ( ; i < array.length; i++ ) {
          //做一个判断,如果说resArray里面没有arr里面的元素,则将arr里面的元素放到resArray里面
          //注意,这边使用的是之前封装好的myIndexOf方法
          if ( myIndexOf( resArray, array[ i ] ) == -1 ) {
            //使用的是前面封装好的push方法
          resArray.push( array[ i ] );
        }
      }
        //将这个数组返回
        return resArray;
      }
      //这边封装的是四种基本选择器,ID选择器,类选择器,通配符选择器,标签选择器
      function basicSelect ( selector, node ) {
        //这边的node指的是要在哪一个下面去寻找selector
        node = node || document;
        var m, res;
        if ( m = rbaseselector.exec( selector ) ) {
          if ( m[ 1 ] ) { // id选择器
            res = document.getElementById( m[ 1 ] );
            if ( res ) {//如果res不是一个空的话,进入
              return [ res ];
            } else {//当res为空的话返回一个空数组
              return [];
            }
          } else if ( m[ 2 ] ) { // class选择器
            return getByClassName( m[ 2 ], node );
          } else if ( m[ 3 ] ) {//通配符选择器
            return node.getElementsByTagName( m[ 3 ] );
          } else if ( m[ 4 ] ) {//标签选择器
            return node.getElementsByTagName( m[ 4 ] );
          }
        }
          return [];
      }
      //封装一个组合选择器,这里面的标签使用逗号隔开的
      function select ( selector, results ) {
        results = results || [];
        var m, temp, selectors, i, subselector;
        //这边是如果传入的selector不是一个字符串的话,那么返回空数组
        if ( typeof selector != 'string' ) return results;
        // 表明参数都没有问题, 接下来就是如何选择
        // 首先判断 qsa 是否可用
        // 然后再 一步步的 自己实现
        if ( support.qsa ) {//如果系统有querySelectorAll方法,那么就使用
        push.apply( results, document.querySelectorAll( selector ) );
        } else {
          // 不存在再来考虑自己实现
          //首先将传入的参数以逗号隔开,放到一个数组里面
          selectors = selector.split( ',' );
          // 循环遍历这个数组
        for ( i = 0; i < selectors.length; i++ ) {
          //在这个循环里面对数组里面的每一个元素进行一个去除空格的操作,保证数据是我们想要的形式
          subselector = myTrim( selectors[ i ] );
          // 接下来就是 处理 subselector,使用正则进行判断
        if ( rbaseselector.test( subselector ) ) {
          // 基本选择器
          //如果匹配到了就将匹配到的传入到基本的四种选择器函数只中,返回一个数组,将这个数组进行一个push
        push.apply( results, basicSelect( subselector ) );
        } else {
          //如果匹配不到那么就使用 select2 函数
          select2( subselector, results );
          }
        }
      }
        // 返回 result注意,这个数组要进行一个去重操作
        return unique( results );
      }
      //封装一个后代选择器的函数,传入两个参数
      function select2 ( selector, results ) {
        results = results || [];
        //将这个参数以逗号隔开
        var selectors = selector.split( ' ' );
        //声明一个数组,这个数组用于存放元素,以及一个node数组,这个数组用于存放从哪一个元素开始找
        var arr = [], node = [ document ];
        for ( var j = 0; j < selectors.length; j++ ) {
          for ( var i = 0; i < node.length; i++ ) {
          //因为这边寻找的是后代选择器,所以只要找到最后面的并将其返回就可以了
          push.apply( arr, basicSelect( selectors[ j ], node[ i ] ));
          }
        //在结束的时候将arr里面的值全部给node,要注意此时node里面的值的作用是什么
        node = arr;
        //将arr清空
        arr = [];
        }
        //在最后将最后一次获取到的node值赋给results
        //这里面的值是最后一次获取到的元素,也就是说是要获取的子代元素中的的最后一个元素
        push.apply( results, node );
        return results;
        }
        return select;
      })();

  • 相关阅读:
    Mego(02)
    Mego(01)
    ThoughtWorks(中国)程序员读书雷达 —— 书籍下载整理
    Spring源码编译一次性通过&遇到的坑解决方法
    Elasticsearch怎么修改索引字段类型?
    Flume 自定义拦截器 多行读取日志+截断
    用Hibernate框架把hql生成可执行的sql语句-Oracle方言
    深入浅出SQL Server中的死锁 [转于CareySon]
    第一次迭代随笔
    结对编程代码分析
  • 原文地址:https://www.cnblogs.com/199316xu/p/6424996.html
Copyright © 2011-2022 走看看