首页 > 代码库 > 山寨HTML5API classList类

山寨HTML5API classList类

preface

觉得自己去写一些类,你真的会找到自己不足的地方。其实厉害不是你实现一个类,而是你如何去设计一个类,能让开发者更加容易操作。对于这个操作样式,可以通过javascript访问style,可是在《javascript高级程序设计》中有讲到这样子CSS、javascript、HTML耦合度太高,不太适合维护;还有就是通过className,但是我们知道className是一个可以被开发者读写的字符串,如果要增删查改元素对应的className的话,可以实现,但是比较麻烦。这个时候HTML5站出来了,提出了classList类,确实方便我们开发者去使用,但是它有一个弊端就是兼容性不是很好。

introduction

简单介绍element.classList,下面是它的4个方法
1 add a class to an element‘s list of classes(为元素添加class)
2 remove a class from an element‘s list of classes(删除元素的class)
3 toggle the existence of a class in an element‘s list of classes ?See below about the optional     second argument.(切换元素的class)
4 check if an element‘s list of classes contains a specific class(检查元素是否有这个class)

确实觉得这样的API让开发者少做很多苦力活,详细的可以去看element.classList,毕竟上面不是我想深入了解的知识点,我想深入了解的是,自己先去模仿别人设计的API,看自己能不能扩展那个API(很显然自己还没达到那种程度)。

description

在这里说明下我定义的CSSClassList可以到我《javascript正则表达式 "\b"问题》找,这里我就不详述了。我们主要还是来实现上面说的4个方法,可以在不支持classListAPI的浏览器上用

一 contains方法(个人觉得这个方法是最重要的,之后的add remove和toggle方法都要用到)

CSSClassList.prototype.contains = function(cls) {

var classname = this.el.className, reg = new RegExp("\\b" + cls + "\\b");

return reg.test(classname);

}

遇见的问题:

  • 1 在《javascript正则表达式 "\b"问题》其实有提到一个比较容易忽略的问题就是对于字符串"\b"与"\\b"的区别。
  • 2 如何将一个字符串转换成正则表达式

解决问题(1就是对应上面的问题1,以此类推)

  • 1 在《javascript正则表达式 "\b"问题》有说道,这里不再详述。
  • 2 在我脑海中现在有两种方法,一种是用eval,但是因为安全性还有性能问题被我否决了,所以我改成了第二种方法是用RegExp构造函数。如果对于现在正在读我的blog的您来说,有更好的方法请告诉我,大家来交流交流。
二 add方法

CSSClassList.prototype.add = function(cls) {

var classname = this.el.className;

if (this.contains(cls))

return;

else {

var arr = classname.split(/\s+/);

arr.push(cls);

this.el.className = arr.join(" ");

}}

设计思路: 

     如果在该元素中找到class的话,就不添加了。找不到就添加,如何去添加?我把该元素的className字符      串转成数组,然后使用数组的push方法并把数组转换成字符串赋值给该元素的className

遇见的问题:

  • 对于字符串的split方法不是很熟练,比如上面有句代码我写成了var arr = classname.split("/\s+/");记住在split参数中是正则表达式但是我又画蛇添足加了双引号""。

解决问题:

  • String.prototype.split()
三 remove方法(这个方法还是我折腾比较久的)

CSSClassList.prototype.remove = function(cls) {

var classname = this.el.className;

if (!this.contains(cls))

return -1;

else {

//indexOf还是有兼容性问题

var arr = classname.split(/\s+/), index = arrIndexOf(arr, cls);

arr.splice(index, 1);

this.el.className = arr.join(" ");

return (this.el.className);

}

}
设计思路:找不到要删除的class就返回-1,然后确定该元素有这个class,就要去找那个class是在哪,然后把它删除掉。还是那样子先把该元素的className转换成数组,然后可以用到ES5的Array.prototype.indexOf方法找到class对应的下标,但是被我否决了,因为这个indexOf只能在IE9+才能用,如过IE9+能用的话,其实就没必要去实现山寨的classList,因为IE9+本身就支持,那怎么办?下面会详述。找到对应的下标就用数组的splice去删除该class并把删除后的数组转换成字符串赋给该元素的className

遇到问题

  • 主要还是怎么用原生的javascript去实现indexOf方法?

解决问题

  • function arrIndexOf(arr, searchEl) {

    if (arr.indexOf) {

      return arr.indexOf(searchEl);

     } else {

      for (var i = 0, len = arr.length; i < len; i++) {

        if (arr[i] === searchEl)

          return i;

     }

      return -1;

     }

    }

就不用我过多去解释了吧,应该看完代码很容易懂吧,我也不是什么大牛级,所以我写的代码还是很平易近人的。
四 toggle方法

CSSClassList.prototype.toggle = function(cls) {

if (!this.contains(cls))

  this.add(cls);

else

  this.remove(cls);

}

这个就不说了,一看就知道了。

summary

在写这个类的时候确实还是遇到很多问题,但是总是能一一解决。我觉得一个程序员最重要的是他的解决问题的能力吧。毕竟自己写的类也不是很多,可能是自己的处女作吧,还是会有许多问题出现的,有空的话,我会看看其他大牛写的代码,然后两者再比较,有对比才有差距才有进步。