前面发过一版,漏了个最重要的代码文件color.js,现在补上。
以下是整个color-picker的完整版
由于UI需求,需要使用直接取色的取色器面板,有点类似于element-plus里的el-color-pick,但是不需要有展开的操作。于是模仿element-plus写了该组件。技术栈vue3.js + javascript
该组件包含三个部分:
- 一个饱和度 - 明度(SV)面板,用于调整颜色的饱和度和明度;
- 用于调整颜色色相(hue 值)的滑块;
-
用于调整颜色透明度(alpha 值)的滑块。
代码实现包含:index.vue、SvPanel.vue、HueSlider.vue、AlphaSlider.vue、utils.js、color.js(新增)
目录
调整颜色色相(hue 值)的滑块代码:HueSlider.vue
调整颜色透明度(alpha 值)的滑块代码:AlphaSlider.vue
入口代码:index.vue
<template>
<div class="color-dropdown__main-wrapper">
<SvPanel ref="svPanel" :color="state.color"></SvPanel>
<HueSlider ref="hueSlider" :color="state.color"></HueSlider>
</div>
<AlphaSlider ref="alphaSlider" :color="state.color"></AlphaSlider>
</template>
<script setup>
import {
reactive,
onBeforeUnmount,
onMounted,
watch,
ref,
computed,
} from "vue";
import SvPanel from "./SvPanel.vue";
import HueSlider from "./HueSlider.vue";
import AlphaSlider from "./AlphaSlider.vue";
import Color from "/public/native/core/color.js";
const state = reactive({
color: new Color(),
});
const emits = defineEmits({
change: null,
});
const alphaSlider = ref(null);
let colorValue = computed(() => {
const hue = state.color.get("hue");
const value = state.color.get("value");
const saturation = state.color.get("saturation");
const alpha = state.color.get("alpha");
return { hue, value, saturation, alpha };
});
let props = defineProps({
modelValue: {
type: String,
required: false,
default: "#ffffff",
},
});
watch(
() => colorValue,
(colorValue) => {
alphaSlider.value.update();
let alpha = colorValue.value.alpha
? colorValue.value.alpha / 101
: 0.99;
emits("change", {
color: state.color.tohex(),
alpha,
});
},
{ deep: true }
);
watch(
() => props.modelValue,
(modelValue) => {
console.log("modelValue-change:", modelValue);
state.color.fromHex(modelValue);
}
);
onMounted(() => {
state.color.fromHex(props.modelValue);
});
onBeforeUnmount(() => {
//console.log('onBeforeUnmount')
});
</script>
<style scoped lang="less">
.color-dropdown__main-wrapper {
margin-bottom: 3px;
display: flex;
&:after {
content: "";
display: table;
clear: both;
}
}
</style>
饱和度 - 明度(SV)面板代码:SvPanel.vue
<template>
<div
class="color-svpanel"
:style="{
backgroundColor: state.background,
}"
>
<div class="color-svpanel__white"></div>
<div class="color-svpanel__black"></div>
<div
class="color-svpanel__cursor"
:style="{
top: state.cursorTop + 'px',
left: state.cursorLeft + 'px',
}"
>
<div></div>
</div>
</div>
</template>
<script setup>
import {
reactive,
onBeforeUnmount,
onMounted,
getCurrentInstance,
computed,
watch,
} from "vue";
import { draggable, getClientXY } from "./utils.js";
let { vnode } = getCurrentInstance();
let props = defineProps({
color: {
type: Object,
required: true,
},
});
const state = reactive({
cursorTop: 0,
cursorLeft: 0,
background: "hsl(0, 100%, 50%)",
});
let colorValue = computed(() => {
const hue = props.color.get("hue");
const value = props.color.get("value");
return { hue, value };
});
watch(
() => colorValue.value,
() => {
update();
}
);
onMounted(() => {
draggable(vnode.el, {
drag: (event) => {
handleDrag(event);
},
end: (event) => {
handleDrag(event);
},
});
update();
});
onBeforeUnmount(() => {
//console.log('onBeforeUnmount')
});
function update() {
const saturation = props.color.get("saturation");
const value = props.color.get("value");
const el = vnode.el;
const { clientWidth, clientHeight } = el;
state.cursorLeft = (saturation * clientWidth) / 100;
state.cursorTop = ((100 - value) * clientHeight) / 100;
state.background = `hsl(${props.color.get("hue")}, 100%, 50%)`;
}
function handleDrag(event) {
const el = vnode.el;