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;
      })();

  • 相关阅读:
    UVA 254 Towers of Hanoi
    UVA 701 The Archeologists' Dilemma
    UVA 185 Roman Numerals
    UVA 10994 Simple Addition
    UVA 10570 Meeting with Aliens
    UVA 306 Cipher
    UVA 10160 Servicing Stations
    UVA 317 Hexagon
    UVA 10123 No Tipping
    UVA 696 How Many Knights
  • 原文地址:https://www.cnblogs.com/199316xu/p/6424996.html
Copyright © 2011-2022 走看看