本实例中的web拾色器功能使用css3实现页面效果,即在页面上显示的元素用css3样式来实现的。再使用js生成拾色器颜色数据,并控制各元素的鼠标事件。当事件作为反应时,获取到对应的数据并显示颜色值。

拾色器的html元素分为三个部分,分别是拾色区域、色系区域和颜色显示区域,如图所示:

web拾色器三个部分的html元素如下:

<div class="color_container">
<div class="main_wrap"> <!--拾色区域-->
<div class="main_drag" id="mainDrag"></div>
<div class="main_con" id="mainCon">
<div class="left_white_bg bg"></div>
<div class="bottom_black_bg bg"></div>
</div>
</div>
<div class="side_wrap"> <!--色系区域-->
<div class="side_drag" id="sideDrag"></div>
<div class="side_con" id="sideCon"></div>
</div>
<div class="show_color" id="findColor"><!--显示区域-->
<div class="color_full" id="colorFull"></div>
<div class="color_text" id="colorText">
R:<input type="text" readonly>
G:<input type="text" readonly>
B:<input type="text" readonly>
</div>
</div>
</div>

加上一些css样式实现图片上的布局效果:

.color_container {width:610px;background:#333;padding:10px;font-size:0;margin:30px auto;}
.color_container>div{display:inline-block;background:#fff;vertical-align:top;box-shadow:0px 0px 5px 0px #999;}
.color_container .main_con{width:550px;height:430px;}
.color_container .main_con .bg{position:absolute;top:0;right:0;bottom:0;left:0;} .color_container .side_con{width:50px;height:430px;}
.color_container .main_wrap,.color_container .side_wrap{position:relative;}
.color_container .side_wrap{margin-left:10px;}
.color_container .main_drag,.color_container .side_drag{position:absolute;border:1px solid #fff;background:rgba(0,0,0,.3);cursor:pointer;}
.color_container .main_drag{width:12px;height:12px;border-radius:50%;z-index:3;left:-7px;top:-7px;}
.color_container .side_drag{height:6px;width:54px;border-radius:2px;left:-3px;top:-4px;}
.color_container .find_color{width:60px;height:60px;position:absolute;top:0;left:-70px;background:#fff;}
.color_container .show_color{display:block;margin:10px 0 0;height:auto;padding:10px;}
.color_container .color_full{display:inline-block;width:58px;height:58px;border:1px solid #ccc;}
.color_container .color_text{display:inline-block;margin-left:30px;height:60px;line-height:60px;text-align:center;font-size:14px;vertical-align:top;}
.color_container .color_text input{width:24px;margin:0 15px 0 5px;}

接下来使用css3的 linear-gradient 线性渐变来修改色系区域元素的背景颜色。色系规则是 红>黄>绿>青>蓝>紫>红,共经过了6次变化,每次变化比例是16%-17%之间,所以可以从上至下添加这七个渐变颜色,增加的css代码如下:

.color_container .side_con{background:linear-gradient(to bottom,red 0%,#ff0 17%,lime 33%,cyan 50%,blue 66%,#f0f 83%,red 100%)}

此时效果如图所示:

拾色区域一般默认颜色是红色系,所以先给拾色区域添加红色背景,代码如下:

.color_container .main_con{background:red;}

此时效果如图所示:

一般拾色器的拾色区域显示规则是,从上至下由明到暗;从左至右由浅到深。这种效果可以添加两个 linear-gradient 透明渐变实现,代码如下:

.color_container .main_con .left_white_bg{background:linear-gradient(to right,#fff 0%,transparent 100%)}
.color_container .main_con .bottom_black_bg{background:linear-gradient(to bottom,transparent 0%,#000 100%);}

此时已经实现最终静态效果如图所示:

此时web拾色器页面效果是有了,但还缺少交互,不能改变拾色区域背景及选择颜色,接下来通过js来实现交互效果。

因为鼠标在拖动吸管选择颜色是每个像素移动的,所以需要根据色系区域高度来计算颜色值并存储备用,代码如下所示:

//色系存储数据
var aColorSeries = {
r:[255],g:[0],b:[0]
}
//色系数据变化
var aColorVary = ['g','r','b','g','r','b'];
//色系元素
var eSeries = document.getElementById('sideCon');
//每个色系颜色变化次数
var nSeriesLen = Math.floor(eSeries.offsetHeight / 6);
//每次变化步长值
var nStep = Math.floor(255 / nSeriesLen);
//步长值剩余值
var nStepRemainder = 255 / nSeriesLen - nStep;
//循环存储色系rgb颜色值
for(let i=0;i<aColorVary.length;i++){
let add = (i % 2); //因为高度不能整除,需要使最终色系填满元素
let nFull = 0; //计算剩余的步长值
for(let j=0;j<nSeriesLen+add;j++){
nFull += nStepRemainder;
let nAddStep = nStep;
if(nFull>1){ //剩余步长值超过1时,每次增加步长值加1
nAddStep = nStep + 1;
nFull = nFull - 1;
}
//遍历色系数据对象添加颜色值
for(let k in aColorSeries){
let nVal = 0;
let nOldVal = aColorSeries[k][aColorSeries[k].length-1];
if(k==aColorVary[i]){
if(add==0){ //判断颜色值改变方向是变大还是变小
nVal = nOldVal + nAddStep;
}else{
nVal = nOldVal - nAddStep;
}
if(nVal > 255){ //限制最大值255
nVal = 255;
}else if(nVal < 0){ //限制最小值为0
nVal = 0;
}
}else{
nVal = nOldVal;
}
aColorSeries[k].push(nVal);
}
}
}

在色系区域吸管上加上拖拽功能,代码如下所示:

//获取拾色区域
var eMainCon = document.getElementById('mainCon');
//获取色系吸管
var eSideDrag = document.getElementById('sideDrag');
//获取吸管高度
var nSideDragH = eSideDrag.offsetHeight;
//获取吸管限制高度
var nSideH = eSeries.offsetHeight - nSideDragH / 2;
//在色系吸管上绑定鼠标按下事件
eSideDrag.addEventListener('mousedown',function(event){
//初始化鼠标开始拖拽的点击位置
var nInitY = event.clientY;
//初始化色系吸管位置
var nInitTop = this.offsetTop;
//色系吸管位置
var nY = null;
//色系选择颜色
var color = null;
document.onmousemove = event=>{
//鼠标移动时取消默认行为,避免选中其他元素或文字
event.preventDefault();
//根据鼠标设置色系吸管位置
nY = event.clientY - nInitY + nInitTop;
//下面的条件限制色系吸管不能超出范围
if(nY >= nSideH-1){
nY = nSideH-1;
}
if(nY <= -nSideDragH/2){
nY = -nSideDragH/2;
}
//因为用的是箭头函数,所以this还是指向滑块,修改滑块位置
this.style.top = nY + 'px'; //修改拾色区背景颜色
let n = nY + nSideDragH / 2;
color = {r:aColorSeries.r[n],g:aColorSeries.g[n],b:aColorSeries.b[n]};
eMainCon.style.background = `rgb(${color.r},${color.g},${color.b})`;
}
//鼠标释放事件
document.onmouseup = event=>{
document.onmouseup = null;
document.onmousemove = null; }
});

此时色系区域的吸管拖动时,拾色区域的背景颜色就会跟着变化,效果如图所示:

在色系区域再加上点击事件,点击时可以把吸管滑动到点击的位置,并修改拾色区域颜色,代码如下所示:

//色系元素绑定点击事件
eSeries.addEventListener('click',function(event){
//获取点击位置
let nY = event.offsetY - nSideDragH/2;
//增加过渡样式,使吸管有滑动效果
eSideDrag.style.transition = '.1s';
//删除过渡样式
setTimeout(e=>{
eSideDrag.style.transition = 'inherit';
},100)
//改变色系吸管位置
eSideDrag.style.top = nY + 'px'; //修改拾色区背景颜色
let n = nY + nSideDragH / 2;
color = {r:aColorSeries.r[n],g:aColorSeries.g[n],b:aColorSeries.b[n]};
eMainCon.style.background = `rgb(${color.r},${color.g},${color.b})`;
});

同样的,拾色区域也需要把颜色存储起来。因为每次选择色系时,拾色区域颜色都会修改,所以用一个函数实现此功能,代码如下所示:

//拾色区域颜色
var aColorMainStore = [];
//获取拾色区域的宽度和高度
var nMainW = eMainCon.offsetWidth;
var nMainH = eMainCon.offsetHeight; function fnColorSet(color){
//重置拾色区域颜色数据
aColorMainStore = []; //左侧可变颜色,默认为白色
var oLeftColor = {r:255,g:255,b:255};
//右侧可变颜色,因为color参数是字符串,所以要转换为数组
var oRightColor = JSON.parse(JSON.stringify(color));
//底部颜色固定黑色
var oBottomColor = {r:0,g:0,b:0};
//因为色块可变颜色从左上角开始,所以默认设置为白色
var oMainColor = {r:255,g:255,b:255};
//Y轴步长值
var oYStep = {
lStep: Math.floor(256 / nMainH), //左侧从上至下是从白色渐变到黑色,所以固定步长值计算
lRemainder: 256 / nMainH - Math.floor(256 / nMainH), //左侧步长剩余值
lAdd:0, //渐变过程添加值
}
//枚举添加右侧从下至下渐变步长值、剩余值及添加值
for(let k in oRightColor){
oYStep[k+'Step'] = Math.floor((oRightColor[k]-oBottomColor[k]+1) / nMainH);
oYStep[k+'Remainder'] = (oRightColor[k]-oBottomColor[k]+1) / nMainH - Math.floor((oRightColor[k]-oBottomColor[k]+1) / nMainH);
oYStep[k+'Add'] = 0;
} //循环每一行色块
for(let i=0;i<nMainH;i++){
//因为每一列的颜色都是往下加深渐变,所以除第一行之外每行循环都需要修改左侧和右侧颜色
if(i>0){
oYStep.lAdd += oYStep.lRemainder;
for(let k in oLeftColor){
//修改左侧颜色
if(oYStep.lAdd>1){
oLeftColor[k] = oLeftColor[k] - (oYStep.lStep + 1);
}else{
oLeftColor[k] = oLeftColor[k] - oYStep.lStep;
}
//修改右侧颜色
oYStep[k+'Add'] += oYStep[k+'Remainder'];
if(oYStep[k+'Add']>1){
oRightColor[k] = oRightColor[k] - (oYStep[k+'Step'] + 1);
//修改添加值
oYStep[k+'Add'] = oYStep[k+'Add'] - 1;
}else{
oRightColor[k] = oRightColor[k] - oYStep[k+'Step'];
}
}
//修改添加值
if(oYStep.lAdd>1){
oYStep.lAdd = oYStep.lAdd - 1;
}
} //每一行的色块颜色单独存到一个新的数组中
aColorMainStore.push([]);
//每一次循环色块都要重置为左侧颜色
oMainColor = JSON.parse(JSON.stringify(oLeftColor)); //x轴步长值
let oXStep = {}
for(let k in oLeftColor){
oXStep[k+'Step'] = Math.floor((oLeftColor[k]-oRightColor[k]) / nMainW);
oXStep[k+'Remainder'] = (oLeftColor[k]-oRightColor[k]) / nMainW - Math.floor((oLeftColor[k]-oRightColor[k]) / nMainW);
oXStep[k+'Add'] = 0;
} //在每一行中循环每一列色块
for(let j=0;j<nMainW;j++){
if(j!=0&&j!=nMainW-1){ //第一个色块颜色和最后一个颜色不需要修改
//从左至右渐变颜色
for(let k in oMainColor){
//逐步修改颜色
oXStep[k+'Add'] += oXStep[k+'Remainder'];
if(oXStep[k+'Add']>1){
oMainColor[k] = oMainColor[k] - (oXStep[k+'Step'] + 1);
oXStep[k+'Add'] = oXStep[k+'Add'] - 1;
}else{
oMainColor[k] = oMainColor[k] - oXStep[k+'Step'];
}
}
}
if(j==nMainW-1){
//最后的颜色设置为右侧颜色值
oMainColor = JSON.parse(JSON.stringify(oRightColor));
} //存储色块颜色
aColorMainStore[i].push(JSON.stringify(oMainColor));
}
}
} //默认颜色为红色背景
fnColorSet({r:255,g:0,b:0});

再给拾色区域的吸管加上拖拽功能,拾色区域加上点击事件,并修改显示区域的颜色及 rgb 的值,代码如下所示:

//获取显示颜色块
var eColorFull = document.getElementById('colorFull');
var eColorText = document.getElementById('colorText');
var aColorInput = eColorText.getElementsByTagName('input');
function fnColorFull(color){
//颜色参数是字符串,需要转换为数组
var color = JSON.parse(color);
// 修改显示颜色
eColorFull.style.background = 'rgb('+color.join(',')+')';
//修改RGB颜色值
for(let i=0;i<aColorInput.length;i++){
aColorInput[i].value = color[i];
}
}
//默认显示白色
fnColorFull('[255,255,255]'); //获取吸管元素
var eMainDrag = document.getElementById('mainDrag');
//aMainColorStore数组中颜色行下标
var nSX = 0;
//aMainColorStore数组中颜色列下标
var nSY = 0;
//获取吸管高度
var nMainDragH = eMainDrag.offsetHeight;
//获取吸管限制宽度
var nMainLimitW = nMainW - nMainDragH / 2;
//获取吸管限制高度
var nMainLimitH = nMainH - nMainDragH / 2;
eMainDrag.addEventListener('mousedown',function(event){
//初始化鼠标开始拖拽的点击位置
var nInitX = event.clientX;
var nInitY = event.clientY;
//初始化吸管位置
var nInitTop = this.offsetTop;
var nInitLeft = this.offsetLeft;
//选中吸管后,在document上绑定鼠标移动事件
document.onmousemove = event=>{
//鼠标移动时取消默认行为,避免选中其他元素或文字
event.preventDefault();
//获取鼠标位置
let nX = event.clientX - nInitX + nInitLeft;
let nY = event.clientY - nInitY + nInitTop;
//以下的条件用于限制吸管不能移出拾色区域
if(nY >= nMainLimitH-1){
nY = nMainLimitH-1;
}
if(nY <= -nMainDragH/2){
nY = -nMainDragH/2;
}
if(nX <= -nMainDragH/2){
nX = -nMainDragH/2;
}
if(nX>=nMainLimitW-1){
nX = nMainLimitW-1;
}
//因为用的是箭头函数,所以this还是指向吸管,修改吸管位置
this.style.top = nY + 'px';
this.style.left = nX + 'px';
//颜色赋值,因为没办法选到最后一个颜色,所以加这个公式,这样中间有些颜色选不到
nSX = nX + nMainDragH/2;
nSY = nY + nMainDragH/2;
//获取当前位置颜色
let oColor = JSON.parse(aColorMainStore[nSY][nSX]);
//填充显示颜色区域
fnColorFull(JSON.stringify([oColor.r,oColor.g,oColor.b]));
}
//松开鼠标后释放document上的事件
document.onmouseup = event=>{
document.onmouseup = null;
document.onmousemove = null;
}
});
//拾色区域绑定点击事件
eMainCon.addEventListener('click',function(event){
//获取点击位置
let nX = event.offsetX - nMainDragH/2
let nY = event.offsetY - nMainDragH/2;
//增加过渡样式,使吸管有滑动效果
eMainDrag.style.transition = '.1s';
//删除过渡样式
setTimeout(e=>{
eMainDrag.style.transition = 'inherit';
},100)
//改变拾色吸管位置
eMainDrag.style.top = nY + 'px';
eMainDrag.style.left = nX + 'px';
//颜色赋值,因为没办法选到最后一个颜色,所以加这个公式,这样中间有些颜色选不到
nSX = nX + nMainDragH/2;
nSY = nY + nMainDragH/2;
//获取当前位置颜色
let oColor = JSON.parse(aColorMainStore[nSY][nSX]);
//填充显示颜色区域
fnColorFull(JSON.stringify([oColor.r,oColor.g,oColor.b]));
});

此时已经可以拖动拾色区域吸管并选择颜色。但此时还没有完全开发完成,因为之前在修改色系的事件中,只是修改了拾色区域的背景,并没有存储拾色区域的颜色,所以需要在色系元素的事件中添加如下代码:

//在色系吸管上绑定鼠标按下事件
eSideDrag.addEventListener('mousedown',function(event){
/*...*/ //鼠标释放事件
document.onmouseup = event=>{
document.onmouseup = null;
document.onmousemove = null;
//设置拾色区颜色
color&&fnColorSet(color);
//获取当前位置颜色
let oColor = JSON.parse(aColorMainStore[nSY][nSX]);
//填充显示颜色区域
fnColorFull(JSON.stringify([oColor.r,oColor.g,oColor.b]));
}
});
//色系元素绑定点击事件
eSeries.addEventListener('click',function(event){
//*...*/ //删除过渡样式
setTimeout(e=>{
eSideDrag.style.transition = 'inherit';
//设置拾色区颜色
color&&fnColorSet(color);
//获取当前位置颜色
let oColor = JSON.parse(aColorMainStore[nSY][nSX]);
//填充显示颜色区域
fnColorFull(JSON.stringify([oColor.r,oColor.g,oColor.b]));
},100) /*...*/
});

一个流畅的web拾色器就完成了,我在代码中都尽可能加上了详细的注释,可以帮助更清晰的理解功能实现逻辑。

使用css3和javascript开发web拾色器实例的更多相关文章

  1. 原生js编写的安全色拾色器

    <html > <head> <meta http-equiv="Content-Type" content="text/html; cha ...

  2. ArcGIS API for JavaScript开发环境搭建及第一个实例demo

    原文:ArcGIS API for JavaScript开发环境搭建及第一个实例demo ESRI公司截止到目前已经发布了最新的ArcGIS Server for JavaScript API v3. ...

  3. Linux下的高级拾色器—Pick

    导读 虽然大多数设计师都在使用 Mac,但也有一少部分在使用 Windows 甚至是 Linux 系统.在 Mac 和 Windows 中都有非常丰富的拾色器工具或插件可用,反而在开源界中这类颜色选择 ...

  4. 使用 HTML5 canvas制作拾色器

    自制的拾色器漂亮吧,哈哈 废话不多说直接上代码,希望可以帮到需要的朋友 <html><head>    <style>        .canvas_color{p ...

  5. 拾色器,可以取出电脑屏幕的任何颜色,ui以及程序员前端等常用软件,文件很小,300K

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985,转载请说明出处. 今天给大家介绍一个小软件,挺实用的,叫做拾色器. 用途:取出电脑屏幕的任意颜色,当你 ...

  6. PS拾色器(前景色背景色)快捷键

    快捷键 I 是拾色器 X 是前后色切换

  7. Android Studio中如何设置颜色拾色器工具

    Android Studio如何设置颜色拾色器工具Color Picker? 你可能下载过一些获取颜色值的一些小工具, 这种方式获取颜色,需要先切换窗口转跳到桌面,然后打开拾色器小工具程序,然后去拾取 ...

  8. 使用JavaScript开发IE浏览器本地插件实例

    使用JavaScript开发IE浏览器本地插件实例 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2015-02-18我要评论 这篇文章主要介绍了使用JavaScript开发IE浏览器本 ...

  9. 优动漫PAINT基础系列之拾色器教学

    在优动漫PAINT中有类似Photoshop的拾色器功能么?在优动漫PAINT中,可以直接输入颜色数值选择颜色么?当然是可以的啦!怎么呼出拾色器界面~ 看这边... 前段时间小编有收到一些小伙伴的疑问 ...

随机推荐

  1. 在kubernetes集群里集成Apollo配置中心(6)之实战使用apollo分环境管理dubbo服务

    生产实践 1.迭代新需求/修复BUG(编码--->提git) 2.测试环境发版,测试(应用通过编译打包发布至test命名空间) 3.测试通过,上线(应用镜像直接发布至prod命名空间) 系统架构 ...

  2. docker的企业级仓库-harbor

    Harbor 一.背景 Docker中要使用镜像,我们一般都会从本地.Docker Hub公共仓库或者其它第三方的公共仓库中下载镜像,但是出于安全和一些内外网的原因考虑,企业级上不会轻易使用.普通的D ...

  3. CodeForces - 13E(分块)

    Little Petya likes to play a lot. Most of all he likes to play a game «Holes». This is a game for on ...

  4. Eclipce怎么恢复误删类

    选择误删除文件在eclipse所在包(文件夹) 在包上单击右键. 选择restore from local history... 在弹出的对话框中选择需要恢复的文件

  5. GUI编程

    组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事 破解工具 简介 GUI的核心技术:Swing AWT 界面不美观 需要jre环境 为了了解MVC架构 了解监听. AWT 包 ...

  6. js create Array ways All In One

    js create Array ways All In One ES6 const arr = [...document.querySelectorAll(`[data-dom="^div& ...

  7. Next.js SSR Tutorials

    Next.js SSR Tutorials https://codesandbox.io/s/nextjs-demo-h49zt cli $ npx create-next-app ssr-demo- ...

  8. element-ui dialog loading

    element-ui dialog loading 指令方式 服务方式 v-loading 当使用指令方式时,全屏遮罩需要添加fullscreen修饰符(遮罩会插入至 body 上),此时若需要锁定屏 ...

  9. 使用 js 实现十大排序算法: 快速排序

    使用 js 实现十大排序算法: 快速排序 QuickSort 快速排序 /** * * @author xgqfrms * @license MIT * @copyright xgqfrms * @c ...

  10. OOP & 模块化, 多态, 封装

    OOP 面向对象编程 (OOP) 是用抽象方式创建基于现实世界模型的一种编程模式.它使用先前建立的范例,包括模块化,多态和封装几种技术. 在 OOP 中,每个对象能够接收消息,处理数据和发送消息给其他 ...