最近在给自己的团队讲解JS类库的知识,因此就跟大家一起共享一下类库的搭建吧。从简单层面的核心功能开始吧,今天要讲解的功能是:如何用原生实现通过类名获取标签。

在这里,利利提醒各位,不要心急,各种复杂的内容都是从简单的内容一步步调整优化过来的,因此我们今天也从最简单的功能出发。

第一步 实现基本功能

在我们学习过的方法中,可以使用getElementsByClassName获取标签,因此,我们直接用这个方法来实现“通过类名获取标签”这一功能。

  1. function getElesByClass(obj, className){
  2.     var result = obj.getElementsByClassName(className);
  3.     return result;
  4. }

第二步 发现兼容问题并进行处理

在使用第一种方法之后,我们发现getElementsByClassName的方法并不能够兼容所有的浏览器,此时我们只能采用数组的方法进行实现。我们可以通过查找标签名(此时需要用到“通配符[*]选择器”),获取到页面中所有的元素,之后将每个元素的类名与我们需要的类名进行比较,我们将类名相同的元素放置于一个数组当中,从而实现查找的效果。

  1. function getElesByClass(obj, className){
  2.     var result = [];
  3.     if (document.getElementsByClassName) {
  4.         result = obj.getElementsByClassName(className);
  5.     } else {
  6.         var eles = document.getElementsByTagName('*');
  7.         for (var i = 0; i < eles.length; i++) {
  8.             if(eles[i].className == className) {
  9.                 result.push(eles[i]);
  10.             }
  11.         };
  12.     }
  13.     return result;
  14. }

第三步 优化类名

细心的同学肯定发现了,我们上面这个代码还是有问题——对于多个类名的元素并不能够实现比较。因此我们需要在类名比较之前,先对查找到的每个元素进行处理,将每个元素的类型进行切割,利用双for循环的方式,将每个元素的每个类名分别和需要的类名进行比较。

  1. function getElesByClass(obj, className){
  2.     var result = [];
  3.     if (document.getElementsByClassName) {
  4.         result = obj.getElementsByClassName(className);
  5.     } else {
  6.         var eles = document.getElementsByTagName('*');
  7.         var classNameArr = [];
  8.         for (var i = 0; i < eles.length; i++) {
  9.             // 通过空格分隔开每个类名
  10.             classNameArr = eles[i].className.split(" ");
  11.             for (var j = 0; j < classNameArr.length; j++) {
  12.                 if(classNameArr[j] == className) {
  13.                     result.push(eles[i]);
  14.                 }
  15.             };
  16.         };
  17.     }
  18.     return result;
  19. }

第四步 针对通配符进行优化

我们都知道,在写CSS代码时,通常不允许使用通配符,原因在于通配符的查找速度有一定的问题。在这里我们也不能随意使用通配符,因此我们此处需要进行优化,通过增加一个参数,让程序员控制要查找的标签类型,如查找类名为.lgl的p标签。这样的查找,要比不指定标签类型的查找,快很多。另外,我们也必须考虑到程序员不传第三个参数的可能性,并进行相关处理。

  1. function getElesByClass(obj, className, targetEle){
  2.     var result = [];
  3.     var eles = [];
  4.     if (document.getElementsByClassName) {
  5.         eles = obj.getElementsByClassName(className);
  6.         if (targetEle) {
  7.             // 如果有,则需要进行筛选 查找标签名是否一致
  8.             var num = 0;
  9.             for (var i = 0; i < eles.length; i++) {
  10.                 if (eles[i].nodeName.toLowerCase() != targetEle) {
  11.                     continue;
  12.                 };
  13.                 result[num] = eles[i];
  14.                 num++;
  15.             };
  16.         } else {
  17.             result = eles;
  18.         }
  19.     } else {
  20.         if (targetEle) {
  21.             eles = obj.getElementsByTagName(targetEle);
  22.         } else {
  23.             eles = obj.getElementsByTagName('*');
  24.         }
  25.         var classNameArr = [];
  26.         for (var i = 0; i < eles.length; i++) {
  27.             // 通过空格分隔开每个类名
  28.             classNameArr = eles[i].className.split(" ");
  29.             for (var j = 0; j < classNameArr.length; j++) {
  30.                 if(classNameArr[j] == className) {
  31.                     result.push(eles[i]);
  32.                 }
  33.             };
  34.         };
  35.     }
  36.     return result;
  37. }

第五步 利用for-in循环,简化for循环,进行代码优化

  1. function getElesByClass(obj, className, targetEle){
  2.     var result = [], // 存放最终返回值
  3.         eles = [], // 存放获取的筛选前的全部标签
  4.         classNameArr = []; // 处理复合类名

  5.     if (document.getElementsByClassName) {

  6.         eles = obj.getElementsByClassName(className);

  7.         if (targetEle) {
  8.             var num = 0;
  9.             for (var i = 0; i < eles.length; i++) {
  10.                 if (eles[i].nodeName.toLowerCase() != targetEle) {
  11.                     continue;
  12.                 };
  13.                 result[num] = eles[i];
  14.                 num++;
  15.             };
  16.         } else {
  17.             result = eles;
  18.         }
  19.     } else {

  20.         if (targetEle) {
  21.             eles = obj.getElementsByTagName(targetEle);
  22.         } else {
  23.             eles = obj.getElementsByTagName('*');
  24.         }

  25.         for (var i = 0; i < eles.length; i++) {
  26.             classNameArr = eles[i].className.split(" ");

  27.             for (var num in classNameArr) {
  28.                 if(classNameArr[num] == className) {
  29.                     result.push(eles[i]);
  30.                 }
  31.             };
  32.         };

  33.     }
  34.     return result;
  35. }

测试用例

  1. <!doctype html>
  2. <html>
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>H5course - 刘国利 独行冰海</title>
  6.     <link rel="stylesheet" href="../css/reset.css">
  7.     <script src="../js/core.js"></script>
  8. </head>
  9. <body>
  10.     <p class="test">独行冰海 - 利利</p>
  11.     <div id="wrap">
  12.         <div class="test con tit">HTML5</div>
  13.         <p class="con peo1">独行冰海 - 利利</p>
  14.         <p class="con">梦幻雪冰 - 陈能堡</p>
  15.         <p class="test">类库构建</p>
  16.     </div>
  17.     <script>
  18.         var wrap = document.getElementById('wrap');
  19.         console.log(getElesByClass(wrap, 'con', 'p'));
  20.     </script>
  21. </body>
  22. </html>

结束~!