这个都用过吧,效果如图所示: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