1

估计大概两三个月没有这类的关于前端的文章了,一来是觉得自己太菜,二来也是因为自己的懒散,浑浑噩噩的消耗时间却没有收获什么成果。今天因为和一些同学的聊天,突然自己的心情很低落,有一种看不到未来在哪的感觉,所以强行让自己学习,去看js插件怎么写。今天写一个简单的选项卡插件,这个我也是看别人博文学习实现的,然后加一些自己的理解。

一.实现效果

选项卡切换

实现页面的代码
虽说有点简陋,但是可以看到在html文件中,引入我们写的tab.js插件后,实现选项卡切换,就只需一行代码就可以实现了。

二.tab.js结构

先整体看下结构大概是怎样

//一开始当然是创建一个构造函数tab
function Tab(){
  //里面只有一行代码,就是调用自身的初始化方法
  this.init.apply(this,arguments);
}

//需要的属性和方法全部写在prototype里面
Tab.prototype = {
  //属性
  //some code
  //方法
  //some code
}

三.一些方法的实现

  1. 我们在这里没有使用闭包然后立即执行,所以才需要一个初始化函数将属性都初始化,在init中:

  init:function(ela,elb,paramObj){
  //一般在插件中都会有个配置对象,并且有默认值
  this.defaultOptions = {
    curClass:'current',
    type:'mouseover',
    delay:150
  }
  //然后我们会去检测用户有没有传入配置参数,有的话就要使用用户的配置,这里使用到一个extend方法
  this.options = this.extend(this.defaultOptions, paramObj || {})
}

extend实际是一个对象拓展方法,将b对象的属性覆盖到a对象中,在JQ里直接写好了这种方法,但js里没有,需要我们自己去模拟,我们将这个方法写在init外面

extend:function(a,b){
  for(var i in b){
    //这个是检测for循环到的属性是不是b自身的
    if(b.hasOwnProperty(i)){
      a[i] = b[i]
    }
  }
  return a;
}

后面init里就是一些基本的属性,比如获取导航栏的DOM,内容块的DOM,以及他们的子元素还有子元素的个数,后面遍历会用到,具体可在文章附的源码里去看。最后我们要在init中给每个导航绑定事件,一个是触发,一个是取消,取消自然就是onmouseout,触发的话可以传入参数来制定,使用中括号可以解决这个问题

for(var i=0;i<this.tLen;i++){
    this.triggerItem[i]['on' + this.options.type] = this.change(i)
    this.triggerItem[i].onmouseout = function(){
      clearTime(self.timer);
      self.timer = null;
    }
}
  1. 添加类名和消除类名方法
    实现这种切换效果一般采用的方法都是使用类名的添加和消除来实现的,那么对类名的操作方法就很重要了

addClass:function(el,name){
  var arr = [],
       str = el.className,
       arr = str.split(/\s+/),
       len = arr.length,
       name = this.trim(name),
  for(var i=0;i<len;i++){
    if(arr[i] === name){
      //已存在直接返回
      return;
    }
   }
  el.className += ' ' + name;
  el = null; 
}

消除类名方法类似,主要是用到了一个splice方法。

  1. change选项卡切换函数
    这个就是给每个导航栏绑定的函数

这里也是使用了一个闭包,每次都返回一个新函数

change:function(index){
  var self = this;
  return function(){
    self.timer = setTimeout(function(){
        for(var i=0;i<self.tLen;i++){
          if(i == index){
            self.addClass(self.triggerItem[index],self.options.curClass);
            self.listItem[i].style.display = 'block';
          }else{
            self.removeClass(self.triggerItem[i],self.options.curClass);
            self.listItem[i].style.display = 'none';
          }
        }
      },self.options.delay)
  }
}

四.总结

其实这个是非常简单的一个封装,刚开始学习前端的肯定是都做过这种切换效果的,而这个封装就是利用对象原型链的继承,来达到一些方法的复用。其中主要的知识点:
1.每新建一个对象都需要init初始化
2.将需要的属性和方法写在prototype中
3.利用闭包去给dom绑定事件
4.类名的处理要注意细节,比如检测是否已存在,是否有空格等
5.对于一些事件要做延迟处理,事件完成后要注意清理现场

五.最后再说两句

这篇文章实际上没有什么有价值的内容,但我希望它对我而言是一个学习开始,就像刚刚开始学习前端的时候一样,那种纯粹的技术的渴望。还有几个月就要毕业了,才意识到自己的大学真的就这么过去了。就像当时读大一大二的时候,回家和高中同学聚会也才意识到高中真的就这么过去了,哪怕那个人站在面前,你也感觉和当初的他不同了。可没办法这就是成长。当时还想着要是能重来,一定要好好读书,一定要追到同桌妹子。现在大学要过去了,遗憾当然是有,但不会再有那种想重来的想法了,因为哪怕重来也一定差不多,真正重要的是自己心智的变化。不重来照样可以好好读书,不重来照样可以去追求自己喜欢的人,何必把自己限定在一种环境,一种身份上呢。尽管这段时间以来受刺激很多,心情有点低落,但还是要好好努力,好好生活。就像以前一直以为自己写文章肯定没人看的,结果偶尔会有人给你点赞,有人给你回复,也许只是寥寥数语,但对我而言确实莫大的鼓励。希望新的一年自己能不断成长,越来越强大!

源码地址:https://coding.net/u/ly550275...


Sauce
173 声望4 粉丝

一名努力的前端程序er,想要成为一个有趣的人。