本實例中的web拾色器功能使用css3實現頁面效果,即在頁面上顯示的元素用css3樣式來實現的。再使用js生成拾色器顏色數據,並控制各元素的鼠標事件。當事件做爲反應時,獲取到對應的數據並顯示顏色值。css
拾色器的html元素分爲三個部分,分別是拾色區域、色系區域和顏色顯示區域,如圖所示:html
web拾色器三個部分的html元素以下:css3
<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樣式實現圖片上的佈局效果:web
.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%)}
此時效果如圖所示:ide
拾色區域通常默認顏色是紅色系,因此先給拾色區域添加紅色背景,代碼以下:函數
.color_container .main_con{background:red;}
此時效果如圖所示:佈局
通常拾色器的拾色區域顯示規則是,從上至下由明到暗;從左至右由淺到深。這種效果能夠添加兩個 linear-gradient 透明漸變實現,代碼以下:this
.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%);}
此時已經實現最終靜態效果如圖所示:spa
此時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拾色器就完成了,我在代碼中都儘量加上了詳細的註釋,能夠幫助更清晰的理解功能實現邏輯。