当前位置: 首页 > 图文教程 > 网络编程 > Javascript > JS教程:制作颜色梯度和渐变效果

Javascript
javascript实例教程(19) 使用HoTMetal(5)
javascript实例教程(19) 使用HoTMetal(6)
javascript实例教程(19) 使用HoTMetal(7)
javascript实例教程(20) OLE Automation(1)
javascript实例教程(20) OLE Automation(2)
javascript实例教程(20) OLE Automation(3)
javascript实例教程(20) OLE Automation(4)
javascript实例教程(20) OLE Automation(5)
javascript实例教程(20) OLE Automation(6)
javascript实例教程(20) OLE Automation(7)
用javascript实现利用FLASH嵌入声音
javascript版的日期输入控件(6)
javascript设计网页中的下拉菜单
javascript设计漫天雪花
javascript制作浮动的工具条
javascript制作闪烁的边框
javascript模拟游戏中的弹出菜单效果
在IE中使用javascript
利用javascript制作简单动画
首页地址添加到收藏夹(javascript)

Javascript 中的 JS教程:制作颜色梯度和渐变效果


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2010-01-03   浏览: 107 ::
收藏到网摘: n/a

  • 序二(09/11/1)
    近来看了Dean的“Convert any colour value to hex in MSIE”,终于解决了根据关键字获取颜色rgb值的问题。
    顺便把程序也重新整理一番,并使用了最近整理的工具库。
  • 序一(09/03/11)
    很久没写blog,太忙了。没什么时间写复杂的东西,重新把颜色渐变效果写一遍。
    关于颜色的效果一般就两个,颜色梯度变化和颜色动态渐变,前者在ie中一般用滤镜实现。

效果预览

运行代码框

[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]

程序说明

ColorGrads颜色梯度

程序ColorGrads的作用是根据颜色集合和渐变级数生成颜色梯度集合。
渐变级数的意思是分多少步完成渐变。

网页设计中的颜色是用RGB色彩模式呈现的。
在这个模式中每种颜色可以用三个代表红(r)、绿(g)、蓝(b)的颜色值(0到255)来表示。

从w3c的Colors部分看到标准中颜色的表示形式包括:
关键字形式:
em { color: red }
RGB形式:
em { color: #f00 }
em { color: #ff0000 }
em { color: rgb(255, 0, 0) }
em { color: rgb(100%, 0%, 0%) }
以上都是表示同一种颜色(红色)。
关键字形式就是用关键字代表颜色值。
而RGB形式,前两种用的比较多,都是一个"#"后面带16进制表示的颜色值,第三种是用十进制的颜色值,第四种是实际值跟255的百分比形式。

各个浏览器对各种颜色表示形式的获取并不相同:

"color: red"形式:
  ie opera ff chrome/safari
style red red #ff0000 red
currentStyle red "red"    
getComputedStyle   #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
"color: #ff0000"/"color: #f00"形式:
  ie opera ff chrome/safari
style #ff0000/#f00 #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
currentStyle #ff0000/#f00 #ff0000    
getComputedStyle   #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
"color: rgb(255, 0, 0)"/"color: rgb(100%, 0%, 0%)"形式:
  ie opera ff chrome/safari
style rgb(255,0,0) #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)
currentStyle rgb(255,0,0) #ff0000    
getComputedStyle   #ff0000 rgb(255, 0, 0) rgb(255, 0, 0)

基本上得到的值还是按标准的形式显示的,只是有些会自动转换形式。
不过ie的rgb形式跟ff/chrome/safari的不同,数值之间并没有空格。
要特别注意的是opera用currentStyle获取关键字形式得到的颜色值是带双引号的,十分奇怪,要尽量避免使用。

要获取两种颜色的渐变梯度,先要把颜色转化成能用来计算的数值。
GetColor和GetData程序就是用来把符合w3c标准表示的颜色值转化成组合该颜色的红(r)、绿(g)、蓝(b)的颜色数值。
RGB形式的值本身就已经带了rgb的具体数值,只要用正则把值提取出来再转化就可以了。

这个过程在GetData中进行:

function GetData(color) {
    var re = RegExp;
    if (/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.test(color)) {
        //#rrggbb
        return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                return parseInt(x, 16);
            });
    } else if (/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(color)) {
        //#rgb
        return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                return parseInt(x + x, 16);
            });
    } else if (/^rgb\((.*),(.*),(.*)\)$/i.test(color)) {
        //rgb(n,n,n) or rgb(n%,n%,n%)
        return $$A.map([ re.$1, re.$2, re.$3 ], function(x){
                return x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x | 0;
            });
    }
}

注意#rrggbb/#rgb形式得到的是16进制的数值字符,把parseInt的第二个参数设为16就可以指定用16进制来处理字符串转换。
对于rgb(n,n,n)/rgb(n%,n%,n%)的形式,直接取得数值,如果有%就根据百分比计算对应数值就行了。
使用这种形式设置颜色时也要注意,
ie6和ie7允许数字百分比混用,其他不可以(包括ie8);
ie6和ie7可以用空格或逗号分隔数值,其他必须用逗号(包括ie8);
当然我们使用时也应该是按照w3c的标准来设置了。
ps:那个DHTML 手册上写的 EM { color: rgb 1.0 0.0 0.0 } 是不能用的,不要被误导了。

如果是关键字形式那就要另外想方法了,可以用一个字典对象来匹配颜色值,但这样程序会变得很庞大。
ps:可以到 这里看所有颜色名对应的数值
近来dean发表了“Convert any colour value to hex in MSIE”,终于解决了这个难题。
其中的关键是利用queryCommandValue("ForeColor")来获取颜色值(或许做过编辑器的会比较熟悉)。
queryCommandValue 的作用是返回document、range或current selection对于给定命令的当前值。
ForeColor 命令是设置或获取文本时的前景色。

具体的做法是先创建一个textarea:

if (!frag) {
    frag = document.createElement("textarea");
    frag.style.display = "none";
    document.body.insertBefore(frag, document.body.childNodes[0]);
};

ps:由于 ie的document.body.appendChild()导致IE已终止操作bug ,所以要用insertBefore。

然后设置color为要取值的颜色:

try { frag.style.color = color; } catch(e) { return [0, 0, 0]; }

在ie如果设置错误的颜色值会报错,所以这里用try...catch来保证能返回值。

能使用queryCommandValue的包括document、range和current selection。
用createTextRange就可以建立一个range:

color = frag.createTextRange().queryCommandValue("ForeColor");

createTextRange可以用在Body,Button,Input和TextArea。
在dean的方法中是用createPopup().document.body的,好处是不用插入元素到dom。
但createPopup是ie的方法,而TextArea还可以用于getComputedStyle,后面会用到。

这样得到的颜色值是一个数值,这个数字跟颜色的关系是这样的:
例如红色的16进制rgb是ff0000,先转成bgr,即0000ff,然后转成10进制,得到255。
同样粉红色pink是FFC0CB,转成bgr是CBC0FF,10进制是13353215。
ps:使用时要注意queryCommandValue("ForeColor")得到的颜色是bgr排列的,跟一般的不一样。

要得到rgb的值可以把转换过程倒过来获取,不过参考dean的文章有更巧妙的方法:

ret = [ color & 0x0000ff, (color & 0x00ff00) >>> 8, (color & 0xff0000) >>> 16 ];

先用与操作(&)把对应位的数值取出来,再用右移运算符(>>>)把数值移到正确的位置上。

例如粉红色FFC0CB要取得绿(g)的颜色值,用与操作(&)取得对应值,FFC0CB & 0x00ff00得到C000,然后右移8个数位得到C0(16进制的一位相当于二进制的4位),即192。

其他支持document.defaultView的可以直接用getComputedStyle获取color。
从上面各个浏览器获取颜色值的结果可知获取的值都是RGB形式的值,所以可以直接用GetData转换:

ret = GetData(document.defaultView.getComputedStyle(frag, null).color);

注意除了ff,如果元素没有插入dom,用getComputedStyle是获取不了color的,所以元素创建时要顺便插入到body中。

在GetStep用GetColor获得颜色值之后,再根据step就可以获得步长了:

r colors = [], start = GetColor(start), end = GetColor(end),
    stepR = (end[0] - start[0]) / step,
    stepG = (end[1] - start[1]) / step,
    stepB = (end[2] - start[2]) / step;

再根据步长生成集合:

for(var i = 0, r = start[0], g = start[1], b = start[2]; i < step; i++){
    colors[i] = [r, g, b]; r += stepR; g += stepG; b += stepB;
}
colors[i] = end;

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

return $$A.map(colors, function(x){ return $$A.map(x, function(x){
    return Math.min(Math.max(0, Math.floor(x)), 255);
});});

程序支持设置多个颜色的连续变换:

for(var i = 0, n = len - 1; i < n; i++){
    var steps = GetStep( colors[i], colors[i+1], step );
    i < n - 1 && steps.pop();
    ret = ret.concat(steps);
}

注意的是各次变换之间要去掉重复的颜色(steps.pop())。

ColorTrans颜色渐变

有了颜色梯度集合,只需要设个定时器把集合的值依次显示就是一个渐变效果了。
这个渐变有两种效果:颜色渐入(transIn)和颜色渐出(transOut)。
原理就是通过改变_index集合索引属性,渐入时逐渐变大,渐出时逐渐变小:

  transIn: function() {
    this.stop(); this._index++; this._set();
    if(this._index < this._colors.length - 1){
        this._timer = setTimeout($$F.bind( this.transIn, this ), this.speed);
    }
  },
  transOut: function() {
    this.stop(); this._index--; this._set();
    if(this._index > 0){
        this._timer = setTimeout($$F.bind( this.transOut, this ), this.speed);
    }
  },

在_set设置样式程序中修改样式:

var color = this._colors[Math.min(Math.max(0, this._index), this._colors.length - 1)];
this._elem.style[this.style] = "rgb(" + color.join(",") + ")";

其中style属性是要修改的样式属性名,例如颜色是"color",背景色是"backgroundColor"。

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

reset程序就是用来重新生成集合的,同时索引也会设回0:

this._options = options = $$.extend(this._options, options || {});
this._colors = ColorGrads( [options.from, options.to], options.step );
this._index = 0;

程序初始化的时候也会reset一次:

this.reset({
    from: this.options.from || $$D.getStyle(this._elem, this.style),
    to: this.options.to,
    step: Math.abs(this.options.step)
});

如果没有自定义from颜色的话会自动获取当前颜色。

使用技巧

链接标签a的伪类的颜色暂时没有办法直接用dom来修改(除非改class)。
所以在颜色渐变菜单中用了个小技巧,把a的内容和跳转换到td的innerHTML和onclick上实现:

var a = x.getElementsByTagName("a")[0], href = a.href, txt = a.innerHTML;
x.onclick = function(){ location.href = href; }
x.innerHTML = txt;

这样就可以在不影响可用性的情况下实现效果。

在测试过程中还发现一个数组的问题,运行alert([,,].length),在ie会返回3,其他会返回2。
mozilla的Array_Literals 部分查到:
If you include a trailing comma at the end of the list of elements, the comma is ignored.
即如果数组字面量元素集合的最后是逗号,逗号会被忽略掉。

使用说明

ColorGrads的第一个参数是颜色集合,第二个参数是渐变级数。

ColorTrans只要一个参数,要实现渐变的对象,可设置以下属性:
from: "",//开始颜色
to:  "#000",//结束颜色
step: 20,//渐变级数
speed: 20,//渐变速度
style: "color"//设置属性(Scripting属性)
from默认是空值,方便判断自动获取。
其中from、to和step在实例化后要修改的话需要用reset来设置。
具体使用请参考实例。

程序代码

ColorGrads部分:

代码拷贝框

[Ctrl+A 全部选择 然后拷贝]

ColorTrans部分:

代码拷贝框

[Ctrl+A 全部选择 然后拷贝]