虽然网上这样的代码一大把的,但不是自己实现总是不明白其原理,而且许多都是基于这个框架那个框架。需要这么复杂吗?其实许多问题只要会分解,就简单了。HTML其实本来都是很简单的东西,微软提出了DHTML后,把静态变成动态,有些人才被那炫目的效果看傻了眼睛。定一定神,我们把它还原成静态不就行了吗?!就像动画一样,本来都是一帧帧的静止画面。javascript的颜色选择器也一样,其实最开始不就是一个表格吗?!只不过每一个格子的颜色不一样,至于动态效果,我们也可以一步分解成我们可以解决的部分。
打造整体框架
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>跨游览器的颜色选择器</title>
<script type="text/javascript">
/* <![CDATA[ */
/* ]]> */
</script>
<style>
//
</style>
</head>
<body>
</body>
</html>
添加静态多彩表格
姑且是这样叫吧,当我们的脚本检测到我们的页面存在一个ID为"colorpicker"的DIV时,它就会在其里面建立一个两行六格的表格,然后格子里面再套表格,为6X6的规格,在遍历的同时也把格子的背景色也填了。unselectable属性为IE准备的,防止焦点丢失!
添加行为层代码(javascript)
//用于生成颜色选择器的具体内容
var colorPickerHtml = function(){
var _hex = ['FF', 'CC', '99', '66', '33', '00'];
var builder = [];
// 呈现一个颜色格
var _drawCell = function(builder, red, green, blue){
builder.push('<td bgcolor="');
builder.push('#' + red + green + blue);
builder.push('" unselectable="on"></td>');
};
// 呈现一行颜色
var _drawRow = function(builder, red, blue){
builder.push('<tr>');
for (var i = 0; i < 6; ++i) {
_drawCell(builder, red, _hex[i], blue)
}
builder.push('</tr>');
};
// 呈现六个颜色区之一
var _drawTable = function(builder, blue){
builder.push('<table class="cell" unselectable="on">');
for (var i = 0; i < 6; ++i) {
_drawRow(builder, _hex[i], blue)
}
builder.push('</table>');
};
//开始创建
builder.push('<table><tr>');
for (var i = 0; i < 3; ++i) {
builder.push('<td>');
_drawTable(builder, _hex[i]);
builder.push('</td>');
}
builder.push('</tr><tr>');
for (var i = 3; i < 6; ++i) {
builder.push('<td>');
_drawTable(builder, _hex[i])
builder.push('</td>');
}
builder.push('</tr></table>');
builder.push('<table class="color_result">/n/
<tr>/n/
<td class="color_view"></td>/n/
<td class="color_code"></td>/n/
</tr>/n/
</table>');
return builder.join('');
};
#================
#================
window.onload = function(){
var colorpicker = document.getElementById("colorpicker");
colorpicker.innerHTML = colorPickerHtml();
}
添加结构层代码(HTML)
<div id="colorpicker">
</div>
添加表现层代码(CSS)
div#colorpicker table{border-collapse:collapse;margin:0;padding:0;}
div#colorpicker .cell td{height:12px;width:12px;}
.color_result{width:216px;}
.color_view{width:110px;height:25px;}
.color_code{text-align:center;font-weight:700;color:#666;font-size:16px;background:#eee;}
至此,我们的颜色选择器就出来了!
添加动态效果
我们要来在选择器上移动时,表格下面的两个大格子会显示鼠标所在小格的颜色与其颜色值,点击表格则停止选择……一步来吧。先添加事件监听函数。
var addEvent = (function () {
if (document.addEventListener) {
return function (el, type, fn) {
el.addEventListener(type, fn, false);
};
} else {
return function (el, type, fn) {
el.attachEvent('on' + type, function () {
return fn.call(el, window.event);
});
}
}
})();
监听鼠标移动的函数
我们要确保鼠标所在的地方为我们选择器的小格子,因此需要分析事件源是否为td元素。
//事件源函数
var getTarget = function(event){
event = event || window.event;
var obj = event.srcElement ? event.srcElement : event.target;
return obj
}
//用它给颜色选择器绑定mouseover事件
var bindMouseover = function(obj){
addEvent(obj,'mouseover',function(e){
var td = getTarget (e);
var nn = td.nodeName.toLowerCase();
if(nn == 'td'){
//执行相关事件………………
}
});
}
然后我们得找出那两个大表格就行了,它们上面各有一个类名color_view与color_code。问题是如何从DOM中取出它们,我们应该尽量避免遍历这种做法,新的时代带来新的事件,我们也应该开拓一下视野。IE8发布了的今天,新式游览器拥有了许多强悍的查找方案,如querySelector,用法酷似JQuery与Prototype的$()选择器,返回一个DOM对象,IE8,FF3.1,safari4等都支持。还有getElementsByClassName,我也实现了一个跨游览器的,能根据平台自主选择原生方案或Pure DOM方案,具体参见这里。因此继续添加行为层代码,Go Go Go!
var getElementsByClassName = function (searchClass, node,tag) {
/***************略,参见下面的部分*****************/
}
var bindMouseover = function(obj){
addEvent(obj,'mouseover',function(e){
var td = getTarget(e),
nn = td.nodeName.toLowerCase(),//IE会自动转换为大写
colorView,
colorCode;
if(document.querySelector){
colorView = obj.querySelector('td.color_view');
colorCode = obj.querySelector('td.color_code');
}else{
colorView = getElementsByClassName('color_view',obj,'td')[0];
colorCode = getElementsByClassName('color_code',obj,'td')[0];
}
if(nn == 'td'){
colorView.style.backgroundColor = td.bgColor;
colorCode.innerHTML = td.bgColor;
}
});
}
window.onload = function(){
var colorpicker = document.getElementById("colorpicker");
colorpicker.innerHTML = colorPickerHtml();
bindMouseover(colorpicker);
}
至此,鼠标移动时的效果就完成了。需要说明一下,为什么我们构建格子时是用bgcolor而不用style="background-color:#fff",这是因为FF会把颜色值转为RGB格式,会导致与IE的16进制格式不一致,另,RGB所占空间太多,会撑开我们的格子。
接下来就是点击事件了吧,错!因为目前我们这样的布局或设置是违背我们的常识,一般而言,颜色选择器是在我们点击一个按钮才弹出来,然后我们选择了颜色,单击后颜色值就会自动填写在相应的文本域中。不可能是一开始就僵硬地出现在页面上,这样根本没有动态生成的需要。因此我们得修改我们的结构层。
修改结构层的body部分。
<body>
<form action="" method="post">
<input type="text" value="点击弹出颜色选择器" id="color"/>
</form>
</body>
修改行为层代码,让文本框获得焦点时弹出颜色选择器
window.onload = function(){
var textfield = document.getElementById('color');
var picker = document.createElement('div');
picker.setAttribute("id","colorpicker");
picker.innerHTML = colorPickerHtml();
var body = document.getElementsByTagName("body")[0];
body.insertBefore(picker,null);
picker.style.display = 'none';
bindMouseover(picker);
addEvent(textfield ,'focus',function(){
textfield.style.position = 'relative';
picker.style.position = 'absolute';
picker.style.display = 'block';
picker.style.left = textfield.offsetLeft + 'px';
picker.style.top = (textfield.clientHeight + textfield.offsetTop)+ 'px';
});
}
绑定单击事件
var bindClick = function(obj,id){
addEvent(obj,'click',function(e){
var td = getTarget(e),
nn = td.nodeName.toLowerCase(),//IE会自动转换为大写
textfield = document.getElementById(id);
if(nn == 'td'){
textfield.value = td.bgColor;
obj.style.display = 'none';
}
});
}
修改onload事件
window.onload = function(){
var textfield = document.getElementById('color');
var picker = document.createElement('div');
picker.setAttribute("id","colorpicker");
picker.innerHTML = colorPickerHtml();
var body = document.getElementsByTagName("body")[0];
body.insertBefore(picker,null);
picker.style.display = 'none';
bindMouseover(picker);
bindClick(picker,"color");
addEvent(textfield ,'focus',function(){
textfield.style.position = 'relative';
picker.style.position = 'absolute';
picker.style.display = 'block';
picker.style.left = textfield.offsetLeft + 'px';
picker.style.top = (textfield.clientHeight + textfield.offsetTop)+ 'px';
});
}

至此,我们的跨游览器颜色选择器就完成了,你也可以把javascript与CSS分离出来,这就更符合web标准了。当然你也可以利用我提供的addSheet函数把样式与脚本都统统打包到一个文件中,减少网页的请求数。最后我们打包用一个类,当作UI组件来使用!
colorpicker.js
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
var extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
return destination;
}
var ColorPicker = Class.create();//我们的富文本编辑器类
ColorPicker.prototype = {
initialize:function(options){
this.setOptions(options);
this.drawPicker(this.options.textfield_id);
},
setOptions:function(options){
this.options = { //这里集中设置默认属性
id:'colorpicker'+ new Date().getTime(),
textfield_id:null//用于textarea的ID,也就是我们的必选项
}
extend(this.options, options || {});//这里是用来重写默认属性
},
ID:function(id){
return document.getElementById(id)
},//getElementById的快捷方式
CE:function(s){
return document.createElement(s)
},//createElement的快捷方式
hide:function(el){
el.style.display = 'none';
},
show:function(el){
el.style.display = 'block';
},
//用于生成颜色选择器的具体内容
colorPickerHtml : function(){
var _hex = ['FF', 'CC', '99', '66', '33', '00'];
var builder = [];
// 呈现一个颜色格
var _drawCell = function(builder, red, green, blue){
builder.push('<td bgcolor="');
builder.push('#' + red + green + blue);
builder.push('" unselectable="on"></td>');
};
// 呈现一行颜色
var _drawRow = function(builder, red, blue){
builder.push('<tr>');
for (var i = 0; i < 6; ++i) {
_drawCell(builder, red, _hex[i], blue)
}
builder.push('</tr>');
};
// 呈现六个颜色区之一
var _drawTable = function(builder, blue){
builder.push('<table class="cell" unselectable="on">');
for (var i = 0; i < 6; ++i) {
_drawRow(builder, _hex[i], blue)
}
builder.push('</table>');
};
//开始创建
builder.push('<table><tr>');
for (var i = 0; i < 3; ++i) {
builder.push('<td>');
_drawTable(builder, _hex[i]);
builder.push('</td>');
}
builder.push('</tr><tr>');
for (var i = 3; i < 6; ++i) {
builder.push('<td>');
_drawTable(builder, _hex[i])
builder.push('</td>');
}
builder.push('</tr></table>');
builder.push('<table id="color_result"><tr><td id="color_view"></td><td id="color_code"></td></tr></table>');
return builder.join('');
},
addEvent:function(el, type, fn ) {
if(!+"/v1") {
el['e'+type+fn]=fn;
el.attachEvent( 'on'+type, function() {
el['e'+type+fn]();
} );
}else{
el.addEventListener( type, fn, false );
}
},
drawPicker:function(id){
var $ = this,
textfield = $.ID(id),
colorPicker = $.CE("div");
colorPicker.className = "colorpicker";
colorPicker.innerHTML = $.colorPickerHtml();
textfield.parentNode.insertBefore(colorPicker,null);
$.hide(colorPicker);
$.addEvent(textfield,'focus',function(){
textfield.style.position = 'relative';
$.show(colorPicker);
var l = textfield.offsetLeft + 'px',
t = (textfield.clientHeight + textfield.offsetTop)+ 'px';
if(/msie|MSIE 6/.test(navigator.userAgent)){
var iframe = $.CE("<iframe id='picker_mask' style='left:"+l
+";width:220px;filter:mask();position:absolute;"+";top:"+t
+"height:180px;z-index:1;'></iframe>");//z-index不能为负数
textfield.insertAdjacentElement('afterEnd',iframe);
}
colorPicker.style.left =l ;
colorPicker.style.top = t ;
})
$.addEvent(colorPicker,'mouseover',function(){
var e = arguments[0] || window.event,
td = e.srcElement ? e.srcElement : e.target,
nn = td.nodeName.toLowerCase(),
colorView = $.ID('color_view'),
colorCode = $.ID('color_code');
if( 'td' == nn){
colorView.style.backgroundColor = td.bgColor;
!+"/v1"? (colorCode.innerText = td.bgColor):(colorCode.innerHTML = td.bgColor);
}
});
$.addEvent(colorPicker,'click',function(){
var e = arguments[0] || window.event,
td = e.srcElement ? e.srcElement : e.target,
nn = td.nodeName.toLowerCase();
if(nn == 'td'){
textfield.value = td.bgColor;
$.hide(colorPicker);
var iframe = $.ID("picker_mask");
iframe && iframe.parentNode.removeChild(iframe);
}
});
addSheet('/
div.colorpicker {display:none;position:absolute;width:216px;border:2px solid #c3c9cf;background:#f8f8f8;}/
div.colorpicker table{border-collapse:collapse;margin:0;padding:0;width:100%;}/
div.colorpicker table td {padding:0!important;}/
div.colorpicker .cell td{height:12px;width:12px;}/
#color_result{width:216px;}/
#color_view{width:110px;height:25px;}');
}
}
window.onload = function(){
new ColorPicker({textfield_id:"color"});
}
最后, 我们得注意一个地方: !+"/v1"? (colorCode.innerText = td.bgColor):(colorCode.innerHTML = td.bgColor);,也就是绑定鼠标在颜色选择器的格子上移动时的事件代码。在IE中,tabel及其td、th的innerHTML是个只读属性,这点非常奇特与恶心,这时我们给它赋值时会报错,我们可以用innerText代替!