写在开头
哈喽,各位好吖!👻
当前,2024年08月08日,是个不错的日子,八八八你发我也发。😂
近来有些感冒😷,状态不佳,过得有点浑浑噩噩!自己上药店买药吃,每次上药店买一两盒药(999和咳嗽糖浆)就要近百,真是挺贵!难怪都说穷人生不起病,这确实呀。
人生箴言"小病就治,大病就嘎"。😋
还有,最近是奥运期间,不知道你是否有关注?😀
都说近这些年,好像全世界对奥运会都不怎么关心了,申办的城市也越来越少了。奥运会下届是在美国洛杉矶,而下下届是在"唯一"申办的澳大利亚布里斯班城市,唯一申办❗😐
不管如何,还是希望未来能继续办下去吧。反正俺是挺喜欢看的,咱最喜欢看游泳、跳水、乒乓球等赛事,感觉奥运赛事带来的体验,远远超过竞技本身。
好,回到正题,这次要分享的是颜色选择器相关的内容,具体效果如下,请诸君按需食用。
(动态被压缩了,颜色区域有点裂痕,真实页面是不会的🥶)
简介
颜色选择器,一个用来选择颜色的小工具,现在的浏览器也都有内置颜色选择器,如:
<input type="color" />
样子长这样:
不错,简单、实用,可惜的是,样子不能自定义,这就很难受了。😅
为此,手动来学会自己搞一个还是很有必要的,接下来就让咱们一步一步来完成它,冲。
基本布局
咱们最终目标是开头看到的那个动图效果,其中最核心的就是选择区那部分,先来进行布局:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container">
<div class="draggable"></div>
</div>
</body>
</html>
创建 style.css 文件:
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.container {
border: 1px solid #cbd5e1;
border-radius: 4px;
position: relative;
width: 250px;
height: 200px;
box-sizing: border-box;
margin-bottom: 20px;
/* 设置背景,渐变了一下 */
background-image: linear-gradient(to bottom, transparent, black), linear-gradient(to right, white, transparent);
background-color: hsl(0, 100%, 50%);
}
.draggable {
width: 20px;
height: 20px;
border: 2px solid #fff;
border-radius: 50%;
position: absolute;
top: -10px;
left: -10px;
transform: translate(0, 0);
cursor: move;
user-select: none;
box-sizing: border-box;
background-color: #000;
}
效果:
创建拖动元素
有了布局后,第二步,咱们要让小黑点变成可拖动的元素。
拖动,又是拖动呢,最近写的文章好像老是和拖动搭边,曾经小编一听到拖动就感觉好麻烦,要处理多个事件,还有各种位置相关的属性,老是傻傻分不清。。。🙊
还是老样子,监听鼠标三兄弟事件(mousedown/mousemove/mouseup),如下:
<script>
document.addEventListener('DOMContentLoaded', () => {
const containerDOM = document.querySelector('.container');
const draggableDOM = document.querySelector('.draggable');
draggableDOM.addEventListener("mousedown", handleMouseDown);
const { width: containerWidth, height: containerHeight } = containerDOM.getBoundingClientRect();
let dx = 0;
let dy = 0;
function handleMouseDown(e) {
const startPos = {
x: e.clientX - dx,
y: e.clientY - dy,
};
function handleMouseMove(e) {
let dxTemp = e.clientX - startPos.x;
let dyTemp = e.clientY - startPos.y;
dx = limitRange(dxTemp, 0, containerWidth);
dy = limitRange(dyTemp, 0, containerHeight);
// 进行移动
draggableDOM.style.transform = `translate3d(${dx}px, ${dy}px, 0)`;
}
function handleMouseUp() {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
}
/** @name 限制一个数值在某个范围内 **/
function limitRange(val, min, max) {
return Math.max(min, Math.min(max, val));
}
});
</script>
效果:
很简单吧,计算了一下鼠标的拖动距离(dx/dy),然后通过 translate 让小黑点元素变得可拖动。当然,这里你也能选择用 top/left 属性,或者是 margin 属性都行。😉
在使元素可拖动之后,接下来咱们要讨论颜色的选择功能。但在实现颜色选择之前,让我们先来简单了解一下"颜色模型"。
颜色模型
颜色模型,是用来表示颜色的数学模型。
常见的颜色模型有三种 RGB、HSL、HSV ,而在前端仅支持前两者,不支持 HSV 模型。
RGB 是应用最广泛的颜色模型。
模型的应用形式:
RGB模型:rgb、rgba、hex。HSL模型:hsl、hsla。HSV模型:hsv、hsva。
含义:
r:红-red,值范围0~255。g:绿-green,值范围0~255。b:蓝-blue,值范围0~255。a:透明度-alpha,值范围0~1。h:色调、色相-hue,值范围0~360。s:饱和度-saturation,值范围0~100%。l:亮度-lightness,值范围0~100%。v:明度-value,值范围0~100%。
具体前端应用情况:
rgb:代表红、绿、蓝值, 如rgb(0, 0, 0)。rgba:增加透明度,如rgb(0, 0, 0, 1)。hex:RGB的16进制的表现形式,如#000、#000000、#000000bb。hsl:代表色调、饱和度、亮度,如hsl(0, 100%, 50%)。hsla:增加透明度,如hsl(0, 100%, 50%, 1)。hsv:代表色调、饱和度、明度,前端不支持。hsva:增加透明度,前端不支持。
大概了解一下就行,这些形式都能互相转换来转换去,转换方法也都是现成可靠的,咱们只要记住常用的 rgb 与 hex 这两种形式就够了。😉
颜色的选择
在上面,咱们实现了用户拖动选择颜色的交互,拥有了 dx 与 dy 变量,它们是相对于容器的偏移量。
咱们要如何把这两个偏移量转换成需要的颜色值呢❓
那必然是需要一些计算滴😋,先来瞅瞅具体代码实现吧,如下:
<script src="./utils.js" ></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
// ...
function handleMouseDown(e) {
// ...
function handleMouseMove(e) {
// ...
// 转换成颜色的变化
handleChangeSaturationValue();
draggableDOM.style.transform = `translate3d(${dx}px, ${dy}px, 0)`;
}
// ...
}
/** @name 初始化一个颜色,黑色 **/
const initColor = {
r: 0,
g: 0,
b: 0,
a: 1,
};
/** @name 最终选择的颜色 **/
let color = {
...initColor,
...rgbToHsv(initColor),
}
/** @name 拖动选择颜色时,饱和度与明度的变化 **/
function handleChangeSaturationValue() {
// 计算饱和度
const s = 100 * dx / containerWidth;
// 计算明度
const v = 100 * (1 - (dy / containerHeight));
// 转换成rgb
const rgb = hsvToRgb({ h: color.h, s, v });
const colorResult = {
...color,
...rgb,
s,
v,
};
color = colorResult;
console.log(color)
};
});
<script>
创建 utils.js 文件:
function rgbToHsv({ r, g, b }) {
const max = Math.max(r, g, b);
const d = max - Math.min(r, g, b);
if (d === 0) {
return {
h: 0,
s: max ? d / max : 0,
v: max,
};
}
let h = 0;
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = 2 + (b - r) / d;
break;
case b:
h = 4 + (r - g) / d;
break;
}
return {
h: h * 60,
s: max ? d / max : 0,
v: max,
};
}
效果:
可以看到当拖动时,颜色具体数值是计算出来了,关键代码是这两行:
const s = 100 * dx / containerWidth;
const v = 100 * (1 - (dy / containerHeight));
这里的 s 和 v 表示饱和度和明度(或者某种颜色分量,亮度)的。
饱和度(Saturation)和明度/亮度(Value 或 Lightness)是 HSV/HSL 颜色模型中的两个组成部分,其中:
- 饱和度(S)表示颜色的纯度,范围从0%(灰色)到100%(完全饱和的颜色)。
- 明度(V)或亮度(L)表示颜色的明暗程度,范围也是从0%(黑色)到100%(白色)。
饱和度(S)的计算:
dx / containerWidth计算了水平偏移量占容器宽度百分比。- 乘以100将这个百分比转换为0到100的饱和度范围。
- 结果是,当用户在颜色选择器水平方向上从左(0%)移动到右(100%),饱和度值
s也会从0增加到100。
明度(V)的计算:
dy / containerHeight计算了垂直偏移量占容器高度百分比。1 - (dy / containerHeight)反转了垂直偏移量,这样当用户从顶部(暗,即低亮度)移动到底部(亮,即高明度)时,亮度值会增加。- 乘以100同样将这个百分比转换为0到100的亮度范围。
- 结果是,当用户在颜色选择器垂直方向上从顶部(0%)移动到底部(100%),亮度值
v也会从100减少到0。
计算亮度
l:const l = 100 * (1 - (dy / containerHeight));,与亮度v是一样的。
有了饱和度 s 与 明度 v ,咱们就可以将 HSV 型转换成 RGB 颜色模型了。🙊
不对吧,不是还有色调 h 还没有算吗❓
先不管它,先使用初始化的默认值就行。因为在实际应用中,色调 h 通常是通过另一个独立控制(比如一个色轮或者一个水平条)来选择的。😕
现在我们只是 console 颜色数值,为了更好的展示效果,我们来将其进行格式化一下,并实时展示到页面上。
结构:
<div class="color-info">
<div id="rgb"></div>
<div id="rgba"></div>
<div id="hex"></div>
<div id="hsl"></div>
<div id="hsv"></div>
</div>
样式:
.color-info {
width: 250px;
border: 1px solid #cbd5e1;
border-bottom: none;
border-radius: 4px;
}
.color-info > div {
width: 100%;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
border-bottom: 1px solid #cbd5e1;
}
逻辑实现:
// ...
// 获取颜色值展示的元素
const rgbDOM = document.getElementById('rgb');
const rgbaDOM = document.getElementById('rgba');
const hexDOM = document.getElementById('hex');
const hslDOM = document.getElementById('hsl');
const hsvDOM = document.getElementById('hsv');
// ...
function handleChangeSaturationValue() {
// ...
// console.log(color);
// 展示颜色值到页面
colorFormat = transformColorFormat(colorResult);
};
/** @name 转换颜色格式 **/
let colorFormat = {
...transformColorFormat(color),
};
/** @name 获取颜色的各种格式 **/
function transformColorFormat(color) {
// 颜色值保持整数
const r = Math.round(color.r);
const g = Math.round(color.g);
const b = Math.round(color.b);
const h = Math.round(color.h);
const s = Math.round(color.s);
const v = Math.round(color.v);
// 由于透明度范围是0~1,为了获得更精确的结果,将其乘以1000,然后除以1000
const a = Math.round(color.a * 1000) / 1000;
// 各种颜色格式
const rgbColor = `rgb(${r} ${g} ${b})`;
const rgbaColor = `rgba(${r} ${g} ${b} / ${a})`;
const hexColor = rgbToHex({ r, g, b, a });
const hslColor = `hsl(${h} 100% 50%)`;
const hsvColor = `${h} ${s}% ${v}% ${a}`;
// 展示到页面
rgbElement.innerText = rgbColor;
rgbaElement.innerText = rgbaColor;
hexElement.innerText = hexColor;
hslElement.innerText = hslColor;
hsvElement.innerText = hsvColor;
return {
rgbColor,
rgbaColor,
hexColor,
hslColor,
hsvColor,
}
}
增加工具函数,utils.js 文件:
function rgbToHex({ r, g, b, a }) {
const [rr, gg, bb, aa] = [r, g, b, Math.round(a * 255)].map((v) =>
v.toString(16).padStart(2, "0")
);
return ["#", rr, gg, bb, aa === "ff" ? "" : aa].join("");
}
效果:
拖动事件封装
完成颜色选择后,接下来咱们要来实现色调选择器,它是一个水平条,允许左右拖动进行选择。
那么,它也需要监听鼠标三兄弟事件(mousedown/mousemove/mouseup)。
后面,咱们还有一个透明度选择器,也是一样的拖动操作。😳
如果每次都监听这三个事件处理拖动逻辑未免有点太麻烦了,我们需要把这个过程给它封装一下,让它更方便一些。
且看,创建 draggable.js 文件:
class Draggable {
constructor(el) {
this.el = el;
this.parentEl = null;
this.parentRect = {};
this.dx = 0;
this.dy = 0;
this.isDragging = false;
this.init();
}
init() {
this.parentEl = this.el.parentNode;
// 给父元素添加点击事件
this.parentEl.addEventListener('click', this.handleClick.bind(this));
this.parentRect = this.parentEl.getBoundingClientRect();
this.el.addEventListener('mousedown', this.handleMouseDown.bind(this));
}
handleClick(e) {
// 仅本身触发
if (e.target === e.currentTarget) {
const dx = e.offsetX;
const dy = e.offsetY;
// 在拖动过程可以自定义做一些事情
if (typeof this.onClick === 'function') {
this.dx = dx;
this.dy = dy;
this.onClick({
dx: this.dx,
dy: this.dy
});
}
}
}
handleMouseDown(e) {
// 阻止冒泡
e.stopPropagation();
this.isDragging = true;
this.startPos = {
x: e.clientX - this.dx,
y: e.clientY - this.dy,
};
document.addEventListener('mousemove', this.handleMouseMove.bind(this));
document.addEventListener('mouseup', this.handleMouseUp.bind(this));
}
handleMouseMove(e) {
e.stopPropagation();
if (this.isDragging) {
const dxTemp = e.clientX - this.startPos.x;
const dyTemp = e.clientY - this.startPos.y;
const { width: parentWidth, height: parentHeight } = this.parentRect;
// 在拖动过程可以自定义做一些事情
if (typeof this.onMouseMove === 'function') {
this.dx = this.clamp(dxTemp, 0, parentWidth);
this.dy = this.clamp(dyTemp, 0, parentHeight);
this.onMouseMove({
dx: this.dx,
dy: this.dy
});
}
}
}
handleMouseUp(e) {
e.stopPropagation();
this.isDragging = false;
document.removeEventListener("mousemove", this.handleMouseMove);
document.removeEventListener("mouseup", this.handleMouseUp);
}
/** @name 外部用来监听事件的函数 **/
on(eventName, callback) {
if (eventName === 'mousemove') {
this.onMouseMove = callback;
}
if (eventName === 'click') {
this.onClick = callback;
}
}
/** @name 外部设置偏移量的函数 **/
setDraggablePostion(dx, dy) {
this.dx = dx;
this.dy = dy;
}
clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
}
主要是对 mousedown/mousemove/mouseup 三个事件进行了简单的封装,这应该难度不是很大哈。😋
噢,还有😶,里面有一点逻辑是对容器点击 click 事件的处理,因为后面也会用到,就先写出来了。
具体使用:
<script src="./draggable.js" ></script>
<script src="./utils.js" ></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
// ...
const draggableInstance = new Draggable(draggableDOM);
draggableInstance.on('mousemove', ({ dx, dy }) => {
handleChangeSaturationValue(dx, dy);
draggableDOM.style.transform = `translate3d(${dx}px, ${dy}px, 0)`;
});
// ...
function handleChangeSaturationValue(dx, dy) { ... }
});
替换掉 handleMouseDown 函数与 dx/dy 变量,并给 handleChangeSaturationValue() 函数增加两个参数即可。
色调选择器
进行了简单的封装后,瞬间觉得简洁很多😀,而色调选择器的实现就比较简单了。
结构:
<div class="container__hue">
<div class="draggable__hue"></div>
</div>
样式:
.container__hue {
width: 250px;
height: 16px;
border-radius: 4px;
margin-bottom: 20px;
position: relative;
background-image: linear-gradient(
to right,
rgb(255 0 0),
rgb(255 255 0),
rgb(0 255 0),
rgb(0 255 255),
rgb(0 0 255),
rgb(255 0 255),
rgb(255 0 0)
);
}
.draggable__hue {
width: 16px;
height: 16px;
border-radius: 50%;
cursor: move;
user-select: none;
position: absolute;
top: 0;
left: -8px;
border: 2px solid #fff;
box-sizing: border-box;
background-color: red;
}
逻辑实现:
const draggableHueDOM = document.querySelector('.draggable__hue');
const draggableHueInstance = new Draggable(draggableHueDOM);
draggableHueInstance.on('mousemove', ({ dx }) => {
draggableHueDOM.style.transform = `translate(${dx}px, 0)`;
});
效果:
几行代码就能实现拖动选择了,秒!😋
但是,还没完❗我们需要把选择的色调给"反馈"到颜色中,也就要计算出具体的色调 h 的值。
先看看具体的实现过程:
draggableHueInstance.on('mousemove', ({ dx }) => {
// 根据dx偏移量计算h
handleChangeHue(dx);
draggableHueDOM.style.transform = `translate(${dx}px, 0)`;
});
/** @name 拖动选择色调时,计算色调h的具体数值 **/
function handleChangeHue(dx) {
const h = (dx / containerWidth) * 360;
const rgb = hsvToRgb({
h,
s: color.s,
v: color.v,
});
const colorResult = {
...color,
...rgb,
h,
};
color = colorResult;
colorFormat = transformColorFormat(colorResult);
}
上面,我们讲过色调的值范围是0~360,通过 dx / containerWidth 能计算出水平偏移量占容器宽度的百分比,在看看这个百分比占据360的多少就能很轻松计算出色调 h 的值了。
增加工具函数,utils.js 文件:
function hsvToRgb({ h, s, v }) {
s /= 100;
v /= 100;
const i = ~~(h / 60);
const f = h / 60 - i;
const p = v * (1 - s);
const q = v * (1 - s * f);
const t = v * (1 - s * (1 - f));
const index = i % 6;
const r = [v, q, p, p, t, v][index] * 255;
const g = [t, v, v, q, p, p][index] * 255;
const b = [p, p, t, v, v, q][index] * 255;
return { r, g, b };
}
这种工具函数网上找现成,或者直接问问AI就行,不用太去琢磨。👻
效果:
这就能看到色调 h 的值在变化了,但还是没完呢❗
上面的颜色选择区域是不是也应该要跟着变才对吧?不能一直是红黑色调,要紧跟步伐才是。🏃
再来改改:
draggableHueInstance.on('mousemove', ({ dx }) => {
handleChangeHue(dx);
draggableHueDOM.style.transform = `translate(${dx}px, 0)`;
// 更新颜色选择区域的变化
updatePageView();
});
/** @name 统一更新页面视图 **/
function updatePageView() {
containerDOM.style.backgroundColor = colorFormat.hslColor;
}
咱们在 colorFormat 变量中存储了很多颜色格式,有 rgbColor/rgbaColor/hexColor/hslColor/hsvColor,可以直接将 hslColor 格式赋值给了颜色选择区域。
效果:
很棒!😋
透明度选择器
接下来就还有透明度选择器了,直接开整!👀
结构:
<div class="container__alpha">
<div class="draggable__alpha"></div>
</div>
样式:
.container__alpha {
width: 250px;
height: 16px;
border-radius: 4px;
margin-bottom: 20px;
position: relative;
background: linear-gradient(to right, rgb(0 0 0 / 0), rgb(0 0 0 / 1)) top left / auto auto,
conic-gradient(
#666 0.25turn,
#999 0.25turn 0.5turn,
#666 0.5turn 0.75turn,
#999 0.75turn
)
top left / 16px 16px repeat;
}
.draggable__alpha {
width: 16px;
height: 16px;
border-radius: 50%;
cursor: move;
user-select: none;
position: absolute;
top: 0;
left: -8px;
border: 2px solid #fff;
box-sizing: border-box;
background-color: #000;
}
呃...这里这个背景稍微有一点麻烦,相信 linear-gradient 函数用于渐变大家或多或少还是有所了解的,而 conic-gradient 也是用于渐变的函数,只是它的方向不一样。这里小编也是从MDN上抄下来的,反正呢,Em...就是多练习吧。😂
逻辑实现:
const draggableAlphaDOM = document.querySelector('.draggable__alpha');
const draggableAlphaInstance = new Draggable(draggableAlphaDOM);
draggableAlphaInstance.on('mousemove', ({ dx }) => {
handleChangeAlpha(dx);
draggableAlphaDOM.style.transform = `translate(${dx}px, 0)`;
});
/** @name 拖动选择透明度时,计算透明度a的具体数值 **/
function handleChangeAlpha(dx) {
const a = dx / containerWidth;
const colorResult = {
...color,
a,
};
color = colorResult;
colorFormat = transformColorFormat(colorResult);
}
效果:
由于,透明度的值范围是0~1,所以通过 dx / containerWidth 可以直接计算出透明度 a 的数值,后面的操作就都是同样的。
还有,咱们希望"颜色的选择"与"色调的选择"要能反馈到这透明度上,啥意思呢❓
现在的透明度选择器上一边是透明一边是黑色的,这好像不太对吧?应当是我们选择红色或者蓝色啥的,有一边是透明,有一边要是选择的颜色才是正确的。
如:
具体实现:
draggableInstance.on('mousemove', ({ dx, dy }) => {
// ...
updatePageView();
});
/** @name 统一更新页面视图 **/
function updatePageView(dx) {
containerDOM.style.backgroundColor = colorFormat.hslColor;
containerAlphaDOM.style.background = `linear-gradient(to right, rgb(${color.r} ${color.g} ${color.b} / 0), rgb(${color.r} ${color.g} ${color.b} / 1)) top left / auto auto,conic-gradient(
#666 0.25turn,
#999 0.25turn 0.5turn,
#666 0.5turn 0.75turn,
#999 0.75turn
) top left / 16px 16px repeat`;
}
还是在 updatePageView 函数中统一去更新页面的视图,如果是使用 Vue 或者 React 那直接绑定一下属性就可以了,不用再去操作原生DOM。
可点击选择
在浏览器内置的颜色选择器(<input type="color" />)中,还可以直接点击选择颜色与色调,如下:
咱们肯定也希望自己做的颜色选择器也有这个功能囖,那要来如何实现呢❓
这个时候就要用到我们在封装拖动事件的时候提前埋的雷了。💣
来吧,且看:
draggableInstance.on('click', ({ dx, dy }) => {
handleChangeSaturationValue(dx, dy);
draggableDOM.style.transform = `translate3d(${dx}px, ${dy}px, 0)`;
updatePageView();
});
draggableHueInstance.on('click', ({ dx }) => {
handleChangeHue(dx);
draggableHueDOM.style.transform = `translate(${dx}px, 0)`;
updatePageView();
});
draggableAlphaInstance.on('click', ({ dx }) => {
handleChangeAlpha(dx);
draggableAlphaDOM.style.transform = `translate(${dx}px, 0)`;
updatePageView();
});
给三个实例直接再监听一下点击事件(click)就行,做的事情和 mousemove 事件是一样的。
这里可以考虑考虑再优化一下,两个事件合起来❓😶
效果:
其他细节
讲到这里,其实本章想说的内容也就差不多了,核心主要是颜色选择、色调选择、透明度选择,其余都是一些附加的细节。
Em......再来说说其中的两个稍微重要一点的小细节:
- 其一,背景同步。
观察下面两图:
可以看到,内置的颜色选择器小圆点的背景是与容器背景同步的,而咱们自己的颜色选择器是没有的,体验有点不好。😕
把小圆点背景改成透明不就行了?当然不行,当靠近边框就会露馅,这不是我们所期待的。
正确做法:
/** @name 统一更新页面视图 **/
function updatePageView() {
// ...
draggableDOM.style.backgroundColor = colorFormat.rgbColor;
draggableHueDOM.style.backgroundColor = colorFormat.hslColor;
draggableAlphaDOM.style.background = `linear-gradient(to right, ${colorFormat.rgbaColor}, ${colorFormat.rgbaColor}) top left / auto auto,
conic-gradient(
#666 0.25turn,
#999 0.25turn 0.5turn,
#666 0.5turn 0.75turn,
#999 0.75turn
) ${-draggableAlphaInstance.dx - 4}px -2px / 16px 16px repeat`;
}
效果:
由于透明度选择器背景比较特殊,需要通过其 dx 控制,让小圆点在拖动中看起来背景效果更真实。呃....反正呢,你可以细细观察一下前后的对比,这里小编很难讲得清。🙊
- 其二,初始位置。
现在小圆点的初始位置不太对,如:颜色选择器的小圆点初始化位置应该是在左下角的黑色位置,透明度的小圆点初始化位置应该是在右边为1的位置上。
需要咱们给它们都初始化一下位置:
function init() {
// 颜色区域
const dx = color.s * containerWidth;
const dy = (1 - color.v) * containerHeight;
draggableInstance.setDraggablePostion(dx, dy);
draggableDOM.style.transform = `translate3d(${dx}px, ${dy}px, 0)`;
// 色调(现在不用也可以,因为也是0,但是如果初始颜色不是黑色,那就有问题了,所以还是得加)
const dxHue = color.h * containerWidth;
draggableHueInstance.setDraggablePostion(dxHue);
draggableHueDOM.style.transform = `translate(${dxHue}px, 0)`;
// 透明度
const dxAlpha = color.a * containerWidth;
draggableAlphaInstance.setDraggablePostion(dxAlpha);
draggableAlphaDOM.style.transform = `translate(${dxAlpha}px, 0)`;
updatePageView();
}
init();
再增加一个函数,并直接执行一下。
效果:
现在看起来就比较完美了,收工收工。😋
完整源码
传送门 👈👈👈
至此,本篇文章就写完啦,撒花撒花。

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。