JS教程:制作颜色梯度和渐变效果(3)
如果是关键字形式那就要另外想方法了,可以用一个字典对象来匹配颜色值,但这样程序会变得很庞大。
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())。