原生js封裝colorpicker組件

 這個都用過吧,效果如圖所示: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);複製代碼

js代碼

預期

咱們想要的結果是這樣的git

new ColorPicker($('#color')).init();

// 傳參是一個DOM掛載點複製代碼

這個不太好講,動畫演示一波
github


要完成的邏輯是這樣的,調節bar能夠調整色相層,在顏色盤內能夠拾取對應的顏色數組


如何準確的獲取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各自進行差值便可


到這裏其實就完了,不過還想說點須要額外注意的

補充說明

DOM建立

因爲沒在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

相關文章
相關標籤/搜索