2008年10月13日星期一

表格拖影效果的 JavaScript

在很多地方看到鼠标从某个表格上划过时,表格行的背景色会逐渐地变淡直至消失,感觉非常酷。当时看到了也想做一个,可惜我始终不明白是怎么弄的,后来才知道是生成一定数量的渐变色,再使用 JavaScript 的计时器函数,逐一调用,呵呵。

这里主要涉及一些 RGB 渐变的东西,我是这样处理的:将终止颜色的 RGB 各值与起始颜色的 RGB 各值相减,再除以渐变步长,然后再在起始颜色的基本上将各分量逐步加上该步长。

用这种方法做一个 ColorGradient 的类用于产生渐变色的数组。

/**
 * 色彩渐变
 * @param start   起始颜色,使用 # 颜色表
 * @param end     终止颜色
 * @param step    渐变步长,大于 1 并且小于 200,默认为 16
 */
var ColorGradient = function(start, end, step) {
  this.start = this._toRGB(start);
  this.end = this._toRGB(end);
  this.step = (function() {
      if(!step || step < 1 || step > 200) {
        return 16;
      }
      return step;
    })();
  this.gradient = [];
}

ColorGradient.prototype = {

  // 获得渐变的颜色数组,以 6 位十六进制字符串返回
  getGradient : function() {
    return this._getGradient();
  },

  // 获得所设定的步长值
  getStep : function() {
    return this.step;
  },

  // 测试工作,用于在页面上渐变测试
  test : function() {
    var grad = this._getGradient();
    var n = 400 / this.step;
    var p = document.createElement('div');
    for(var i = 0; i < grad.length; i++) {
      var d = document.createElement('div');
      d.className = 'grad';
      d.style.width = n + 'px';
      d.style.backgroundColor = '#' + grad[i];
      p.appendChild(d);
    }
    document.body.appendChild(p);
  },

  // 生成渐变色数组
  _getGradient : function() {
    if(this.gradient.length > 0) {
      // 如果渐变色变量中有值直接返回
      return this.gradienth;
    }
    // 生成各步的颜色
    for(var i = 0; i <= this.step; i++) {
      var color = this._getNewColor(i).toString(16);
      while(color.length < 6) {
        color = '0' + color;
      }
      this.gradient.push(color);
    }
    return this.gradient;
  },

  // 根据 RGB 变化量获得每步的 RGB 颜色
  _getNewColor : function(k) {
    var rgbStep = this._getStepRgb();
    var rgb = 0;
    for(var i = 0; i < 3; i++) {
      var c = Math.floor(this.start[i] + rgbStep[i] * k);
      rgb |= c << ((3 - i - 1) * 8);
    }
    return rgb;
  },

  // 获得 RGB 三种颜色的变化量
  _getStepRgb : function() {
    var rgb = [];
    // 依次获得 R、G、B 的变化步长
    for(var i = 0; i < 3; i++) {
      rgb.push(this._getStepVar(i));
    }
    return rgb;
  },

  // 根据渐变步长、起始、终止颜色获得步长的变化量
  _getStepVar : function(index) {
    return (this.end[index] - this.start[index]) / this.step;
  },

  /**
   * 将 # 颜色转换成 RGB 颜色数组
   * 索引 0 -- 红色 R
   * 索引 1 -- 绿色 G
   * 索引 2 -- 蓝色 B
   */
  _toRGB : function(color) {
    var v = color.substring(1);
    var c = parseInt(v, 16);
    var rgb = [];
    for(var i = 0; i < 3; i++) {
      rgb.push(c >> ((3 - i - 1) * 8) & 0xff);
    }
    return rgb;
  }
}

上面这个ColorGradient类在生成对象后,调用getGradient()方法就能获得渐变颜色数组,从开始色到终止色。

为了这完成这个程序,还定义了几个工具类,特别是事件处理类。由于浏览器存在差异,各种浏览器中的事件绑定都不一样,比如 IE 中使用attachEvent函数,而 Firefox 中则使用addEventListener这个函数,为了避免这些差异就很有必要构造一些兼容各浏览器的工具方法。

还有一个小问题,在进行事件绑定时,所绑定的事件处理程序只是一个引用,并不能放上参数。比如有handler(str)方法,要将其绑定在objonclick事件上,如果使用obj.onclick = handler;的话,参数没办法传递,如果使用obj.onclick = handler(str);也不对,这样是把hadnler执行后的结果给了事件,如果用obj.onclick = 'handler(str)';这样也是不对的,这样只是把字符串给了事件,那该怎么办呢?

实际上可以通过调用一个方法,这个方法调用后将返回另一个方法引用,这样就能达到我们的目的了。

/**
 * 事件处理工具类
 */
var Event = function(){}

Event = {

  /**
   * 为 element 使用 handler 处理程序添加至 event 事件
   * 兼容 IE 及 Firefox 等浏览器
   *
   * 例如为 botton 对象添加 onclick 事件,使用 clickEvent
   * 方法作为处理程序:
   *   Event.addEvent(botton, 'click', clickEvent);
   *
   * @param element  需要添加事件的对象(Object)
   * @param event    需要添加的事件名称(String),不加“on”
   * @param handler  需要添加的方法引用(Function)
   */
  addEvent : function(element, event, handler) {
    if(element.attachEvent) {
      element.attachEvent('on' + event, handler);
    } else if (element.addEventListener) {
      element.addEventListener(event, handler, false);
    } else {
      element['on' + event] = handler;
    }
  },

  /**
   * 添加事件处理程序时,只能添加一个方法的引用,并不能给
   * 方法加上参数。比如定义了 clickEvent(str) 这个方法,现
   * 在要将其作为 obj 的 onclick 的事件处理程序,就可以用:
   * obj.onclick = Event.getFuntion(null, clickEvent, str);
   */
  getFunction : function(obj, fun) {
    var args = [];
    obj = obj || window;
    for(var i = 2; i < arguments.length; i++) {
      args.push(arguments[i]);
    }
    return function() {
        fun.apply(obj, args);
      };
  }
}

用于表格渐变的代码如下:

/**
 * 封装了拖影效果的类
 * @param id      表格的 id 名
 * @param time    各颜色渐变的时间间隔,默认为 10
 * @param start   起始颜色,默认为 #dcdcdc
 * @param end     结束颜色,默认为 #ffffff
 */
var Table = function(id, time, start, end) {

  // 获得所有的表格行
  this.rows = (function() {
      var tab = $(id);
      if(tab.tBodies.length == 0) {
        return tab.rows;
      }
      var rows = [];
      for(var i = 0; i < tab.tBodies.length; i++) {
        for(var j = 0; j < tab.tBodies[i].rows.length; j++) {
          rows.push(tab.tBodies[i].rows[j]);
        }
      }
      return rows;
    })();

  this.start = start || Table.DEFAULT_START;
  this.end   = end   || Table.DEFAULT_END;
  this.time  = time  || Table.DEFAULT_TIME;

  // 生成渐变色实例
  var color = new ColorGradient(this.start, this.end, 16);

  // 获得渐变色所有的颜色
  this.grad = color.getGradient();

  // 获得渐变的步长
  this.step = color.getStep();
}

// 默认的间隔时间
Table.DEFAULT_TIME = 10;

// 默认的起始颜色
Table.DEFAULT_START = '#dcdcdc';

// 默认的结束颜色
Table.DEFAULT_END = '#ffffff';

Table.prototype = {

  // 为各表格行添加事件
  addEvent : function() {
    for(var i = 0; i < this.rows.length; i++) {

      // 将所有的表格行的背景色设为结束色
      this.rows[i].style.backgroundColor = this.end;

      // 使用 this.overEvent 事件处理程序为表格行添加 onmouseover 事件
      Event.addEvent(this.rows[i], 'mouseover',
          Event.getFunction(this, this.overEvent, this.rows[i]));

      // 使用 this.outEvent 事件处理程序为表格行添加 onmouseout 事件
      Event.addEvent(this.rows[i], 'mouseout',
          Event.getFunction(this, this.outEvent, this.rows[i]));
    }
  },

  // 用于表格行 onmouseover 的事件处理
  overEvent : function(row) {
    row.style.backgroundColor = this.start;
    row.change = this.step;
  },

  // 用于表格行 onmouseout 的事件处理
  outEvent : function(row) {
    // 由于 outEvent 在执行时不属于 Table 这个类中,必须找个变量进行代理引用
    var me = this;
    if(row.change-- > 0) {
      // 逐渐更改背景色
      row.style.backgroundColor = '#' + me.grad[me.step - row.change];

      // 重复执行 outEvent
      setTimeout(function() {
          // 这里使用 me 的 Table 引用,由于 this 在这里所指的是 window 对象      
          me.outEvent(row);
        }, this.time);
    }
  },

  // 调试用代码
  _getRows : function(id) {
    var tab = $(id);
    alert(tab.tBodies.length);
  }
}

这里好像不能上传附件,完整的代码可以到 http://download.csdn.net/source/721339 上下载,如果没有 CSDN 账号或者是无法下载,请联系 frankiegao123@gmail.com

没有评论: