JavaScript 颜色梯度和渐变效果

序二(09/11/1)

近来看了Dean的”Convert any colour value to hex in MSIE“,终于解决了根据关键字获取颜色rgb值的问题。
顺便把程序也重新整理一番,并使用了最近整理的工具库

序一(09/03/11)

很久没写blog,太忙了。没什么时间写复杂的东西,重新把颜色渐变效果写一遍。
关于颜色的效果一般就两个,颜色梯度变化和颜色动态渐变,前者在ie中一般用滤镜实现。

效果预览

颜色梯度变化演示:

简单的颜色拾取器(点击修改梯度演示颜色):

颜色渐变菜单:
Cropper Tween Slider Resize Drag Tooltips

点击随机颜色渐变:

点击随机颜色渐变

程序说明

【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中进行:

JavaScript 颜色梯度和渐变效果JavaScript 颜色梯度和渐变效果Code
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 ]; }

ps:在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就可以获得步长了:

var 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集合索引属性,渐入时逐渐变大,渐出时逐渐变小:

JavaScript 颜色梯度和渐变效果JavaScript 颜色梯度和渐变效果Code
transIn: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部分:

JavaScript 颜色梯度和渐变效果JavaScript 颜色梯度和渐变效果Code
var ColorGrads =(function (){
//获取颜色梯度数据function GetStep(start, end, step) {
var 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 >>8 , (color &0xff0000 )>>>16 ];
}
}
return ret;
}
//获取颜色数组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 ;
});
}
}

return function (colors, step){
var ret =[], len =colors.length;
if ( step ===undefined ) { step =20 ; }
if ( len ==1 ) {
ret =GetStep( colors[0 ], colors[0 ], step );
}else if ( len >1 ) {
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);
}
}
return ret;
}
})();

ColorTrans部分:

JavaScript 颜色梯度和渐变效果JavaScript 颜色梯度和渐变效果Code
var ColorTrans =function (elem, options){

this ._elem =$$(elem);
this ._timer =null ;//定时器this ._index =0 ;//索引this ._colors =[];//颜色集合this ._options ={};//参数对象this ._setOptions(options);

this .speed =Math.abs(this .options.speed);
this .style =this .options.style;

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

this ._set();
};
ColorTrans.prototype ={
//设置默认属性_setOptions:function (options) {
this .options ={//默认值from:””,//开始颜色(默认空值方便自动获取)to:”#000 “,//结束颜色step:20 ,//渐变级数speed:20 ,//渐变速度style:”color “//设置属性(Scripting属性)};
$$.extend(this .options, options ||{});
},
//重设颜色集合reset:function (options) {
//根据参数设置属性this ._options =options =$$.extend(this ._options, options ||{} );
//获取颜色集合this ._colors =ColorGrads( [ options.from, options.to ], options.step );
this ._index =0 ;
},
//颜色渐入transIn:function () {
this .stop();this ._index ++;this ._set();
if (this ._index 0 ){
this ._timer =setTimeout($$F.bind(this .transOut,this ),this .speed);
}
},
//颜色设置_set:function () {
var color =this ._colors[Math.min(Math.max(0 ,this ._index),this ._colors.length -1 )];
this ._elem.style[this .style]=”rgb(“+color.join(“,”)+”)”;
},
//停止stop:function () {
clearTimeout(this ._timer);
}
};

下载完整实例

Original: https://www.cnblogs.com/cloudgamer/archive/2009/03/11/color.html
Author: cloudgamer
Title: JavaScript 颜色梯度和渐变效果

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/535964/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球