原生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

相关文章
相关标签/搜索