這個都用過吧,效果如圖所示:javascript
html結構是這樣子的html
<div class="panel">
<div class="hue">
<div class="saturation mask">
<div class="white mask"></div>
<div class="black mask"></div>
<div class="pointer">
<div></div>
</div>
</div>
</div>
<div class="slider">
<div class="bar">
<div class="mark">
<div></div>
</div>
</div>
</div>
</div>複製代碼
其實你F12審查元素能夠看出那個漸變的色盤不是一層的,一層也作不出來,實際是三層的vue
最底層的色相層,中間的白色遮罩,上層的黑色遮罩java
.saturation {
background-color: #f00;
}
.white {
background: linear-gradient(90deg,#fff,hsla(0, 0%, 100%, 0));
}
.black {
background: linear-gradient(0,#000, transparent);
}複製代碼
那個bar就簡單了,直接漸變OK!node
background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);複製代碼
咱們想要的結果是這樣的git
new ColorPicker($('#color')).init();
// 傳參是一個DOM掛載點複製代碼
這個不太好講,動畫演示一波
github
要完成的邏輯是這樣的,調節bar能夠調整色相層,在顏色盤內能夠拾取對應的顏色數組
告訴你是計算獲得的,經過偏移值差值計算換算成色相值,bar上一共六個色塊區域bash
#f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00app
把它用一個數組存起來,咱們須要作的是知道當在選擇在那個區域,在這個區域的偏移值,一個區域的寬度,而後計算當前的色相值,這也就是爲何數字除了保存關鍵點rgb值還保存了一些0和1,咱們須要知道這個色塊是那個值在遞增遞減。
不知道這要說你是否能夠理解,其實在每一個區間內rgb值只有一個在變化。
let lvl = X / unit | 0;let offset = X % unit;let s = ColorPicker.matrix[lvl];let t = offset / unit * 255;let r = s[0] + s[3] * t | 0;let g = s[1] + s[4] * t | 0;let b = s[2] + s[5] * t | 0;複製代碼
也是經過差值計算,其實只要告訴你邊界的值你就會了,以下圖所示,左上是#FFF,底部都是#000,右上是第一步計算的值,如此一來按rgb各自進行差值便可
到這裏其實就完了,不過還想說點須要額外注意的
因爲沒在html裏寫標籤,結構是js動態建立的,這裏就有講究了,實現的方式有不少
方式一
直接innerHTML = htmlString,這個方式卻是簡單,不過因爲js裏須要獲取一些dom的屬性,這種方式生成後還需從新獲取一下dom,不管是性能仍是代碼書寫感受都不太好。
方式二
經過document.createElement函數建立,這個卻是避免了dom從新獲取,但直接這樣用代碼看着很亂,沒有第一種那種結構清晰,能不能結合一下呢
方式三
嚴格來講仍是方式二,不過這裏作了一下封裝,使用的像vue裏的虛擬dom,用一個數組存這個結構,vnode2dom把這個數組轉成dom結構,其中還使用了ref來標記dom,否則一旦轉換丸找不到要用的dom豈不是jj了,
let arr = [[ 'div', {class:'panel', ref: 'panel'}, [
['div', {class:'hue'}, [
['div', {class:'saturation mask', ref:'saturation'}, [
['div', {class:'white mask'}, []],
['div', {class:'black mask'}, []],
['div', {class:'pointer', ref:'pointer'}, [
['div', {}, []]
]],
]]
]],
['div', {class:'slider'}, [
['div', {class:'bar'}, [
['div', {class:'mark', ref:'mark'}, [
['div', {class:'scale'}, []]
]]
]]
]],
['div', {class:'info',ref:'info'}, []]
]
]]
複製代碼
vnode2Dom(arr, node) {
if (!node) {
node = document.createDocumentFragment();
}
arr.forEach(elt => {
let [el, attr, cont] = elt;
let obj = document.createElement(el);
Object.entries(attr).forEach(el => {
let [name, val] = el;
if (name === 'ref') {
this.refs[val] = obj;
} else {
obj.setAttribute(name, val);
}
})
if (typeof cont === 'undefined' || typeof cont === 'string') {
obj.innerHTML = cont || '';
} else if (Array.isArray(cont)) {
if (cont.length) {
this.vnode2Dom(cont, obj)
}
}
node.appendChild(obj)
})
return node
}複製代碼
---------------------完結---------------------
詳細的代碼移步github:colorpicker