JavaScript 颜色梯度和渐变效果

  程序说明

  【ColorGrads颜色梯度】

  程序ColorGrads的作用是通过StartColor和EndColor生成颜色梯度集合。

  颜色都可以用红(r)、绿(g)、蓝(b)三个颜色来表示。

  程序中先通过GetColor把一般的颜色表示形式转化成一个用红(r)、绿(g)、蓝(b)三个颜色值作元素的集合。

  那就首先要知道有什么颜色表示形式,从w3c的Colors部分可以知道有以下形式:

  关键词模式:

  em { color: red }

  RGB颜色模式:

  em { color: #f00 }

  em { color: #ff0000 }

  em { color: rgb(255,0,0) }

  em { color: rgb(100%, 0%, 0%) }

  以上都是表示同一种颜色(红色)。

  获取颜色属性的形式在ie和ff并不同,ff统一返回RGB颜色模式的第三种形式,ie则按照设置时的形式返回。

  先说说RGB颜色模式,前两种比较常用应该都明白他们的区别吧,它用的是16进制表示形式,而我们想要10进制的。

  把一个16进制表示的字符转成10进制数字,一般用parseInt,在substr截取字符之后就可以用parseInt转换。

  对于#ff0000这个形式可以这样转换:

  

复制代码 代码如下:

  return Map([color.substr(1, 2), color.substr(3, 2), color.substr(5, 2)],

  function(x){ return parseInt(x, 16); }

  )

  parseInt的第二个参数就是第一个参数的进制值。

  对于#f00形式,跟上一个差不多,只是转换之前要先换成完整表示形式:

  

复制代码 代码如下:

  return Map([color.substr(1, 1), color.substr(2, 1), color.substr(3, 1)],

  function(x){ return parseInt(x + x, 16); }

  )

  后面两种可能用的就比较少了,一个用10进制的rgb颜色值表示,另一个用百分比来表示。

  ff严格按照那样的格式来表示,而ie就“放松”很多,例如:

  ie可以允许数字百分比混用,ff不可以;

  ff必须有逗号分隔,ie可以只用空格分隔;

  当然我们使用时最好是按照w3c的标准来设置了。

  ps:那个DHTML 手册上写的 EM { color: rgb 1.0 0.0 0.0 } 根本不能用的,不要被误导了。

  对这个形式,程序用正则取得数值,如果有%就根据百分比计算出对应数值:

  

复制代码 代码如下:

  return Map(color.match(/\d+(\.\d+)?\%?/g),

  function(x){ return parseInt(x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x, 10); }

  )

  而关键词大家都很熟悉,要转化却很麻烦,因为没有一定规律只能一个一个对应:

  

复制代码 代码如下:

  var mapping = {"red":"#FF0000"};//略

  color = mapping[color.toLowerCase()];

  if(color){

  return Map([color.substr(1, 2), color.substr(3, 2), color.substr(5, 2)],

  function(x){ return parseInt(x, 16); }

  )

  }

  在Create创建颜色集合程序中获得开始颜色和结束颜色的数据后,再根据Step(多少步)就可以获得步长了:

  

复制代码 代码如下:

  startColor = this.GetColor(this.StartColor),

  endColor = this.GetColor(this.EndColor),

  stepR = (endColor[0] - startColor[0]) / this.Step,

  stepG = (endColor[1] - startColor[1]) / this.Step,

  stepB = (endColor[2] - startColor[2]) / this.Step;

  再根据步长生成集合:

  

复制代码 代码如下:

  for(var i = 0, n = this.Step, r = startColor[0], g = startColor[1], b = startColor[2]; i < n; i++){

  colors.push([r, g, b]); r += stepR; g += stepG; b += stepB;

  }

  colors.push(endColor);

  正确的颜色值是在0到255之间的,而且是不带小数的,所以最好修正一下:

  

复制代码 代码如下:

  return Map(colors, function(x){ return Map(x, function(x){

  return Math.min(Math.max(0, Math.floor(x)), 255);

  });});

  【ColorTrans颜色渐变】

  有了颜色梯度集合,只需要设个定时器把集合的值依次显示就是一个渐变效果了。

  这个渐变一般是分两个步骤,分别是(FadeIn)和渐出(FadeOut)。

  原理就是通过改变_index集合索引,渐入时逐渐变大,渐出时逐渐变小:

  

复制代码 代码如下:

  //颜色渐入

  FadeIn: function() {

  this.Stop(); this._index++; this.SetColor();

  if(this._index < this._colors.length - 1){

  this._timer = setTimeout(Bind(this, this.FadeIn), this.Speed);

  }

  },

  //颜色渐出

  FadeOut: function() {

  this.Stop(); this._index--; this.SetColor();

  if(this._index > 0){

  this._timer = setTimeout(Bind(this, this.FadeOut), this.Speed);

  }

  },

  在SetColor设置样式程序中,通过CssColor来设置要修改的样式属性,例如字体颜色是"color",背景色是"backgroundColor":

  

复制代码 代码如下:

  var color = this._colors[Math.min(Math.max(0, this._index), this._colors.length - 1)];

  this._obj.style[this.CssColor] = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ")";

  由于颜色集合是根据开始颜色、结束颜色和步数生成的,所以如果要修改这些属性必须重新生成过集合。

  Reset程序就是用来修改这些属性并重新生成集合的,集合重新生成后索引也要设回0:

  

复制代码 代码如下:

  //修改颜色后必须重新获取颜色集合

  color = Extend({ StartColor: this._startColor, EndColor: this._endColor, Step: this._step }, color || {});

  //设置属性

  this._grads.StartColor = this._startColor = color.StartColor;

  this._grads.EndColor = this._endColor = color.EndColor;

  this._grads.Step = this._step = color.Step;

  //获取颜色集合

  this._colors = this._grads.Create();

  this._index = 0;

  使用技巧

  在颜色渐变菜单中,并没有使用链接标签a,原因是a的伪类的颜色并不能直接用js来修改(除非改class)。

  暂时没想到很好的方法,只好用onclick跳转代替了。

  在测试过程中还发现一个关于数组的问题,在ie和ff运行alert([,,].length)会分别显示3和2。

  最后一个元素不写的话ff就会忽略这个元素,只要写的话就不会忽略即使是undefined和null,看了下文档也找到原因。

  所以这个情况还是插一个东西进去,觉得不好看就new Array好了。

  测试中还发现chrome(1.0.154.48)的map一个问题,map是js1.6的Array的方法,ff和chrome都支持(具体看这里)。

  在ff中[,,1].map(function(){return 0})返回的是[0,0,0],但chrome却返回[,,0]。

  即在chrome中如果元素是空(不包括null和undefined)的话就一律返回空,用new Array来创建也一样。

  感觉这样不太合理,应该以后会改进吧。

  使用说明

  

复制代码 代码如下:

  ColorGrads只有3个属性设置:

  StartColor: "#fff",//开始颜色

  EndColor: "#000",//结束颜色

  Step: 20//渐变级数

  设置好属性后用Create生成集合就行了。

  ColorTrans只要一个参数,要实现渐变的对象,可设置以下属性:

  StartColor: "",//开始颜色

  EndColor: "#000",//结束颜色

  Step: 20,//渐变级数

  Speed: 20,//渐变速度

  CssColor: "color"//设置属性(Scripting属性)

  如果不设置StartColor会自动使用CurrentStyle获取的样式值。

  其中StartColor、EndColor和Step在实例化后要重新设置的话需要用Reset来设置。

  程序代码

  ColorGrads部分:

  

复制代码 代码如下:

  var ColorGrads = function(options){

  this.SetOptions(options);

  this.StartColor = this.options.StartColor;

  this.EndColor = this.options.EndColor;

  this.Step = Math.abs(this.options.Step);

  };

  ColorGrads.prototype = {

  //设置默认属性

  SetOptions: function(options) {

  this.options = {//默认值

  StartColor: "#fff",//开始颜色

  EndColor: "#000",//结束颜色

  Step: 20//渐变级数

  };

  Extend(this.options, options || {});

  },

  //获取渐变颜色集合

  Create: function() {

  var colors = [],

  startColor = this.GetColor(this.StartColor),

  endColor = this.GetColor(this.EndColor),

  stepR = (endColor[0] - startColor[0]) / this.Step,

  stepG = (endColor[1] - startColor[1]) / this.Step,

  stepB = (endColor[2] - startColor[2]) / this.Step;

  //生成颜色集合

  for(var i = 0, n = this.Step, r = startColor[0], g = startColor[1], b = startColor[2]; i < n; i++){

  colors.push([r, g, b]); r += stepR; g += stepG; b += stepB;

  }

  colors.push(endColor);

  //修正颜色值

  return Map(colors, function(x){ return Map(x, function(x){

  return Math.min(Math.max(0, Math.floor(x)), 255);

  });});

  },

  //获取颜色数据

  GetColor: function(color) {

  if(/^#[0-9a-f]{6}$/i.test(color))

  {//#rrggbb

  return Map([color.substr(1, 2), color.substr(3, 2), color.substr(5, 2)],

  function(x){ return parseInt(x, 16); }

  )

  }

  else if(/^#[0-9a-f]{3}$/i.test(color))

  {//#rgb

  return Map([color.substr(1, 1), color.substr(2, 1), color.substr(3, 1)],

  function(x){ return parseInt(x + x, 16); }

  )

  }

  else if(/^rgb(.*)$/i.test(color))

  {//rgb(n,n,n) or rgb(n%,n%,n%)

  return Map(color.match(/\d+(\.\d+)?\%?/g),

  function(x){ return parseInt(x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x, 10); }

  )

  }

  else

  {//color

  var mapping = {"red":"#FF0000"};//略

  color = mapping[color.toLowerCase()];

  if(color){

  return Map([color.substr(1, 2), color.substr(3, 2), color.substr(5, 2)],

  function(x){ return parseInt(x, 16); }

  )

  }

  }

  }

  };

  ColorTrans部分:

  

复制代码 代码如下:

  var ColorTrans = function(obj, options){

  this._obj = $(obj);

  this._timer = null;//定时器

  this._index = 0;//索引

  this._colors = [];//颜色集合

  this._grads = new ColorGrads();

  this.SetOptions(options);

  this.Speed = Math.abs(this.options.Speed);

  this.CssColor = this.options.CssColor;

  this._startColor = this.options.StartColor || CurrentStyle(this._obj)[this.CssColor];

  this._endColor = this.options.EndColor;

  this._step = Math.abs(this.options.Step);

  this.Reset();

  this.SetColor();

  };

  ColorTrans.prototype = {

  //设置默认属性

  SetOptions: function(options) {

  this.options = {//默认值

  StartColor: "",//开始颜色

  EndColor: "#000",//结束颜色

  Step: 20,//渐变级数

  Speed: 20,//渐变速度

  CssColor: "color"//设置属性(Scripting属性)

  };

  Extend(this.options, options || {});

  },

  //重设颜色集合

  Reset: function(color) {

  //修改颜色后必须重新获取颜色集合

  color = Extend({ StartColor: this._startColor, EndColor: this._endColor, Step: this._step }, color || {});

  //设置属性

  this._grads.StartColor = this._startColor = color.StartColor;

  this._grads.EndColor = this._endColor = color.EndColor;

  this._grads.Step = this._step = color.Step;

  //获取颜色集合

  this._colors = this._grads.Create();

  this._index = 0;

  },

  //颜色渐入

  FadeIn: function() {

  this.Stop(); this._index++; this.SetColor();

  if(this._index < this._colors.length - 1){

  this._timer = setTimeout(Bind(this, this.FadeIn), this.Speed);

  }

  },

  //颜色渐出

  FadeOut: function() {

  this.Stop(); this._index--; this.SetColor();

  if(this._index > 0){

  this._timer = setTimeout(Bind(this, this.FadeOut), this.Speed);

  }

  },

  //颜色设置

  SetColor: function() {

  var color = this._colors[Math.min(Math.max(0, this._index), this._colors.length - 1)];

  this._obj.style[this.CssColor] = "rgb(" + color[0] + "," + color[1] + "," + color[2] + ")";

  },

  //停止

  Stop: function() {

  clearTimeout(this._timer);

  }

  };

  

   [Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]