技术版本如下:
vue 2.6.14
less 3.13.1
element-ui 2.15.6
less-loader 5.0.0
需求:
支持RGB、HEX编码、支持吸管吸取颜色、颜色选择器、颜色模板、透明度、色板、线性渐变颜色
效果图:
1.引入选择器的color-all文件
<template><div><div><div class="colorpicker-box" :style="{background:handStyle()}"></div></div><h3>带编码显示的color选择器</h3><div> <ColorPicker:data="pickerColor"@update:isLinear="pickerColor.isLinear = $event"@update:direction="pickerColor.direction = $event"@update:leftColor="handUpdateElement($event, 0)"@update:rightColor="handUpdateElement($event, 1)"></ColorPicker></div><h3>无编码显示的color选择器</h3><div><ColorPicker:data="pickerColor":isText="false"@update:isLinear="pickerColor.isLinear = $event"@update:direction="pickerColor.direction = $event"@update:leftColor="handUpdateElement($event, 0)"@update:rightColor="handUpdateElement($event, 1)"></ColorPicker></div></div>
</template>
<script>
import ColorPicker from '@/components/color-modal/color-picker.vue'
export default {components: {ColorPicker,},data() {return {pickerColor: {isLinear: false, //是否线性color: ['#334251'], //选择的颜色direction: 'right', //方向},}},methods: {handStyle() { return this.pickerColor.isLinear ? `linear-gradient(to ${this.pickerColor.direction},${this.pickerColor.color[0]} ,${this.pickerColor.color.length >= 2 ? this.pickerColor.color[1] : '#AE7DFF'})` : this.pickerColor.color[0]},handUpdateElement(value, cursor = null) {this.$set(this.pickerColor.color, cursor, value)},},
}
</script><style lang="less" scoped>
.colorpicker{&-box{width: 200px;border-radius: 5px;height: 30px;}div{padding: 10px;}
}</style>
2.重点,选择器的封装组件文件color-picker.vue
<template><el-popover placement="left-start" width="264" trigger="hover"><div class="colorPickerBody"><!-- tabs --><div class="colorPickerBody-headers"><el-radio-group v-model="activeName" size="mini" @change="handActive"><el-radio-button :label="0">颜色填充</el-radio-button><el-radio-button :label="1">线性填充</el-radio-button></el-radio-group></div><!-- top部分 --><div class="colorPickerBody-top"><div class="colorPickerBody-top-one"><!-- 颜色块color --><div class="color-diamond"><div :style="'background-color: ' +bgColor +';width: 100%;height: 100%;box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15), inset 0 0 4px rgba(0, 0, 0, .25);'"></div></div><!-- select下拉 --><el-dropdown @command="handleCommand" class="eldropdownColor"><span class="el-dropdown-link">{{ colorType }}<i class="el-icon-arrow-down el-icon--right"></i></span><el-dropdown-menu slot="dropdown" :append-to-body="false"><el-dropdown-item command="HEX">HEX</el-dropdown-item><el-dropdown-item command="RGB">RGB</el-dropdown-item></el-dropdown-menu></el-dropdown><div v-if="colorType === 'HEX'"><el-input v-model="bgColor" class="colorValcss" @input="bgColor = $event; handHEXtoRGB($event)"></el-input></div><div v-else class="colorRGBBox"> <el-input type="number" v-model="red" min="0" max="255"class="colorRGBValcss" @input="handredChange"></el-input><el-input type="number" v-model="green" min="0"max="255" class="colorRGBValcss" @input="handgreenChange"></el-input><el-input type="number"v-model="blue" min="0" max="255" class="colorRGBValcss" @input="handblueChange"></el-input></div><div class="strawcss" title="吸管" @click="nativePick"><img src="@/assets/image/strawImg.svg"></div></div><!-- 线性特性box --><div v-if="activeName === 1" class="colorPickerBody-top-two"><div class="colorPickerBody-top-two-body"><div class="colorPickerBody-top-two-body-tag" title="首部" @click="handAlphaColor(true)"><img:src="handLineImg(true)"></div><div class="colorPickerBody-top-two-body-center" :style="'background: linear-gradient(to right, ' + handleftRightColor(true) + ', ' +handleftRightColor(false) +');'"></div><div class="colorPickerBody-top-two-body-tagRight" title="尾部" @click="handAlphaColor(false)"><img:src="handLineImg(false)"></div></div><div class="strawcss iconright" :title="data.direction === 'right' ? '旋转方向:上下' : '旋转方向:左右'"@click="handDirection"><i class="el-icon-refresh-right"></i></div></div><!-- 透明度块 --><div class="colorPickerBody-top-three"><div class="colorPickerBody-top-three-Alpha" ref="saturation_value"><div class="alpha-slider" ref="alpha_slider" @mousedown="mousedownAlpha"><div class="slider" :style="alphaSliderStyle + ';background:' + bgColor"></div><div :style="'background: linear-gradient(to right, rgba(0,0,0,0), ' +bgColor +');width: 100%;height: 100%;border-radius: 10px;'"></div></div></div><div class="colorPickerBody-top-three-number"> <el-input v-model="alpha" class="alphaValcss" type="number"min="0" max="100" @input="handAlpha"> <i slot="suffix" class="suffixInput">%</i></el-input></div></div></div><!-- 中间线 --><div class="colorPickerBody-border"></div><!-- bottom的颜色选择器 --><div class="colorPickerBody-body"><div class="colorPickerBody-body-headers"><div class="colorPickerBody-body-headers-title">颜色选择器</div><div class="colorPickerBody-body-headers-svg"><div :class="colorselecotr ? 'boxbuttom checkbuttom' : 'boxbuttom '" @click="colorselecotr = true"><imgsrc="@/assets/image/colordemo.svg"> </div><div :class="!colorselecotr ? 'boxbuttom checkbuttom' : 'boxbuttom '" @click="colorselecotr = false"><imgsrc="@/assets/image/colorpick.svg"></div></div></div class="colorPickerBody-body-box"><div v-if="colorselecotr"><MyColorSelect class="MyColorSelect" :color="bgColor" :alphaValue="alpha"@update:color="bgColor = $event; handHEXtoRGB($event)"></MyColorSelect></div><ul v-else class="colorDemoList"><li v-for="(item, index) in colorAll" :key="index" :style="'background: ' + item"@click="bgColor = item; handHEXtoRGB(item)"></li></ul></div></div><!-- 仿input框,默认显示第一个color --><div class="colorInputBody" slot="reference" v-if="isText"><div class="colorBox" :style="'background:' + data.color[0]"></div><div class="colorInputBody-title">{{ data.color[0] }}</div></div><div class="colorNoTextBody" slot="reference" v-else><div class="colorNoTextBody-colorBox" :style="'background:' + data.color[0]"></div></div></el-popover>
</template><script>
import MyColorSelect from "./MyColorSelect.vue"
import moveCursorImg from '@/assets/image/moveCursorImg.png'
import checkmoveCursorImg from '@/assets/image/checkmoveCursorImg.png'
import message from "@/utils/message.js";
import { debounce } from '@/utils/util.js'export default {props: {data: {type: Object,default: () => ({isLinear: false, //是否线性color: ["#000"], //选择的颜色direction: "right", //方向}),},//是否显示color编码isText: {type: Boolean,default: true}},components: {MyColorSelect},data() {return {colorAll: ["#FF0000", "#FFA500", "#FFFF00", "#008000", "#0000FF","#4B0082", "#EE82EE", "#FF1493", "#FF69B4", "#FF4500","#FF6347", "#FFD700", "#ADFF2F", "#00FFFF", "#87CEEB","#4169E1", "#800080", "#9932CC", "#8A2BE2", "#FF00FF","#FFC0CB", "#F08080", "#CD5C5C", "#FA8072", "#FFA07A","#FF7F50", "#FFDAB9", "#FFE4B5", "#FFDEAD", "#FFE4E1","#FFF0F5", "#F0FFF0", "#F5FFFA", "#B0E0E6", "#ADD8E6","#87CEFA", "#87CEEB", "#00BFFF", "#1E90FF", "#6495ED","#4682B4", "#5F9EA0", "#20B2AA", "#008B8B", "#008080"],alphaSliderStyle: "left: calc(100% - 6px);",alpha: 100,colorType: "HEX",bgColor: "",colorselecotr: true,activeName: 0,red: 255,green: 0,blue: 0,isLinearStart: true,moveCursorImg,checkmoveCursorImg,hasEyeDrop: 'EyeDropper' in window};},mounted() {this.bgColor = this.data.color[0]this.activeName = this.data.isLinear ? 1 : 0},methods: {handAlphaColor(item) {this.isLinearStart = item;let alphaNew = 1;if (item) {const { r, g, b, a } = this.parseColor(this.data.color[0]);alphaNew = a;} else {const { r, g, b, a } = this.parseColor(this.data.color[1]);alphaNew = a;}this.alpha = alphaNew.toFixed(2) * 100this.handAlpha()},// taghandActive(e) {if (e === 0) {this.bgColor = this.data.color[0]this.handAlphaColor(true)this.$emit('update:isLinear', false)} else {this.$emit('update:isLinear', true)}},// 方向handDirection() {if (this.data.direction === 'right') {this.$emit('update:direction', 'top')} else {this.$emit('update:direction', 'right')}},//取色async nativePick(e) {const val = e ? e.target.value : nullif (val) {console.log('获得颜色: ' + val)} else {const eyeDropper = new window.EyeDropper() // 初始化一个EyeDropper对象try {const result = await eyeDropper.open() // 开始拾取颜色this.bgColor = result.sRGBHex;this.handHEXtoRGB(result.sRGBHex)} catch (e) {console.log('用户取消了取色')}}},//判断线性条handleftRightColor(val) {let color = '#AE7DFF';if (val) {color = this.data.color[0]} else {if (this.data.color.length >= 2) color = this.data.color[1]}return color;},//判断首尾游标handLineImg(val) {let icon = moveCursorImg;if (val) {if (this.isLinearStart) {this.bgColor = this.data.color[0]icon = checkmoveCursorImg;}} else {if (!this.isLinearStart) {this.bgColor = this.data.color.length >= 2 ? this.data.color[1] : '#AE7DFF'icon = checkmoveCursorImg;}}return icon;},handredChange(val) {if ((val ?? '') !== '') {this.bgColor = this.rgba2hex(val, this.green, this.blue, this.matchHexA())this.handHEXtoRGB(this.bgColor)}},handgreenChange(val) {if ((val ?? '') !== '') {this.bgColor = this.rgba2hex(this.red, val, this.blue, this.matchHexA())this.handHEXtoRGB(this.bgColor)}},handblueChange(val) {if ((val ?? '') !== '') {this.bgColor = this.rgba2hex(this.red, this.green, val, this.matchHexA())this.handHEXtoRGB(this.bgColor)}},matchHexA() {let percentage = this.alpha * 0.01;return percentage;},rgba2hex(r, g, b, a = 1) {r = parseInt(r);let r1 =r.toString(16).length !== 2 ? "0" + r.toString(16) : r.toString(16);g = parseInt(g);let g1 =g.toString(16).length !== 2 ? "0" + g.toString(16) : g.toString(16);b = parseInt(b);let b1 =b.toString(16).length !== 2 ? "0" + b.toString(16) : b.toString(16);a = parseFloat(a);let a1 = "";if (a !== 1) {let temp = Math.floor(256 * a);a1 =temp.toString(16).length !== 2? "0" + temp.toString(16): temp.toString(16);}return `#${r1}${g1}${b1}${a1}`.toUpperCase();},handAlpha() {this.alphaSliderStyle = `left: ${this.alpha >= 96 ? "calc(100% - 9px)" : this.alpha + '%'};`;},// 透明度handleChangeAlpha(e) {let w = this.$refs.alpha_slider.clientWidth;let x =e.pageX - this.$refs.saturation_value.getBoundingClientRect().left;x = x < w && x > 0 ? x : x > w ? w : 0;// 计算透明度this.alpha = Math.floor((x / w) * 100 + 0.5);// 移动滑块this.alphaSliderStyle = `left: ${x >= w - 6 ? w - 9 : x}px;`;if (!this.colorselecotr) {this.bgColor = this.rgba2hex(this.red, this.green, this.blue, this.matchHexA())this.handHEXtoRGB(this.bgColor)}},mousedownAlpha(e) {this.handleChangeAlpha(e);window.addEventListener("mousemove", this.handleChangeAlpha);window.addEventListener("mouseup", this.mouseupAlpha);},mouseupAlpha(e) {window.removeEventListener("mousemove", this.handleChangeAlpha);window.removeEventListener("mouseup", this.mouseupAlpha);},handleCommand(command) {this.colorType = command;if (command === "RGB") {this.handHEXtoRGB(this.bgColor)}},isHexColorCode(str) {return /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/.test(str);},handHEXtoRGB: debounce(function (color) {if (!this.isHexColorCode(color)) {message.message("当前非HEX编码,请重新输入!", "error");return}const { r, g, b, a } = this.parseColor(color);this.red = r;this.green = g;this.blue = b;if (this.isLinearStart) {this.$emit('update:leftColor', color)} else {this.$emit('update:rightColor', color)}}, 500),parseColor(color) {if (color) {let r, g, b, a;if (typeof color === "string") {if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8}|[0-9a-fA-F]{3}|[0-9a-fA-F]{4})$/.test(color)) {return this.hex2rgba(color);}} else {r = color.r > 255 ? 255 : color.r < 0 ? 0 : color.r;g = color.g > 255 ? 255 : color.g < 0 ? 0 : color.g;b = color.b > 255 ? 255 : color.b < 0 ? 0 : color.b;a = color.a > 1 ? 1 : color.a < 0 ? 0 : color.a;return { r, g, b, a };}} else {return null;}},hex2rgba(s) {if (/^#?[0-9a-fA-F]{3}$/.test(s)) {let b = s.substring(s.length - 1, s.length);let g = s.substring(s.length - 2, s.length - 1);let r = s.substring(s.length - 3, s.length - 2);return hex2rgba(`${r + r}${g + g}${b + b}`);}if (/^#?[0-9a-fA-F]{4}$/.test(s)) {let a = s.substring(s.length - 1, s.length);let b = s.substring(s.length - 2, s.length - 1);let g = s.substring(s.length - 3, s.length - 2);let r = s.substring(s.length - 4, s.length - 3);return hex2rgba(`${r + r}${g + g}${b + b}${a + a}`);}if (/^#?[0-9a-fA-F]{6}$/.test(s)) {let b = parseInt("0x" + s.substring(s.length - 2, s.length));let g = parseInt("0x" + s.substring(s.length - 4, s.length - 2));let r = parseInt("0x" + s.substring(s.length - 6, s.length - 4));return { r, g, b, a: 1 };}if (/^#?[0-9a-fA-F]{8}$/.test(s)) {let a = parseInt("0x" + s.substring(s.length - 2, s.length));a = a / 255;let b = parseInt("0x" + s.substring(s.length - 4, s.length - 2));let g = parseInt("0x" + s.substring(s.length - 6, s.length - 4));let r = parseInt("0x" + s.substring(s.length - 8, s.length - 6));return { r, g, b, a };}},},
};
</script><style scoped lang="less">
.colorDemoList {width: 100%;list-style-type: none;padding: 13px 0 0 0;margin: 0;li {display: inline-block;width: 16px;cursor: pointer;border-radius: 2px;height: 16px;margin: 0 9px 8px 0;}
}/* 颜色方块 */
.color-diamond {position: relative;width: 24px;height: 24px;border-radius: 2px;overflow: hidden;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAWElEQVRIiWM8fubkfwYygKWJOSM5+mCAhRLNoxaPWjxq8ajFoxbTyeL/DAfJ0Xjs3Cl7Siwmu4Yht1aDgZEYx6MWj1o8avGoxaMWD3qLya5X//4nqx6HAQC7RBGFzolqTAAAAABJRU5ErkJggg==");background-size: 10px 10px;margin-right: 8px;
}.iconright {font-size: 15px;cursor: pointer;
}.strawcss {display: flex;align-items: center;justify-content: center;width: 24px;padding-left: 5px;img {cursor: pointer;}
}.eldropdownColor {width: 56px;color: #fff;}.colorPickerBody {height: 100%;width: 100%;padding: 5px 11px 13px 11px;&-top {padding: 10px 0 12px 0;width: 100%;height: 100%;&-one {display: flex;align-items: center;}&-two {display: flex;align-items: center;justify-content: space-between;padding-top: 12px;width: 100%;&-body {width: 100%;display: flex;flex-direction: row;align-items: center;position: relative;&-tag {position: absolute;left: -1px;top: -2px;cursor: pointer;z-index: 1;}img {width: 14px;height: 18px;}&-tagRight {position: absolute;right: -1px;top: -2px;cursor: pointer;}&-center {left: 6px;position: absolute;width: calc(100% - 12px);height: 12px;box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAWElEQVRIiWM8fubkfwYygKWJOSM5+mCAhRLNoxaPWjxq8ajFoxbTyeL/DAfJ0Xjs3Cl7Siwmu4Yht1aDgZEYx6MWj1o8avGoxaMWD3qLya5X//4nqx6HAQC7RBGFzolqTAAAAABJRU5ErkJggg==");background-size: 10px 10px;}}}&-three {width: 100%;display: flex;justify-content: space-between;align-items: center;padding-top: 20px;&-Alpha {width: 80%}&-number {width: 15%;::v-deep.el-input__suffix {right: 2px;top: 1px;}.suffixInput {color: #fff;font-size: 12px;}.alphaValcss {width: 44px;::v-deep .el-input__inner {text-align: center;height: 24px;font-size: 12px;padding: 0 3px;border-radius: 5px;border: 1px solid #484849;background: #29292cFF;color: #fff;}}}}.colorValcss {width: 119px;::v-deep .el-input__inner {height: 24px;border-radius: 2px 2px 2px 2px;border: 1px solid #484849;background: #29292cFF;color: #fff;}}.colorRGBBox {display: flex;}.colorRGBValcss {width: 40px;::v-deep .el-input__inner {height: 24px;padding: 0 3px;text-align: center;border-radius: 2px 2px 2px 2px;border: 1px solid #484849;background: #29292cFF;color: #fff;}}}&-border {height: 1px;background: #484849;margin: 0 0 12px 0;width: 100%;}&-body {width: 100%;height: 100%;&-headers {display: flex;justify-content: space-between;align-items: center;&-title {color: #fff;font-size: 14px;}&-svg {width: 43px;display: flex;justify-content: space-between;.checkbuttom {background: #3C3C3F;border-radius: 2px 2px 2px 2px;}.boxbuttom {width: 22px;height: 22px;display: flex;justify-content: center;align-items: center;}img {width: 16px;height: 16px;cursor: pointer;}}}}&-headers {::v-deep .el-radio-group {display: flex;}::v-deep .el-radio-button__inner {background: #29292c;border-radius: 2px 2px 2px 2px;border: 1px solid #484849;color: #99999b;width: 116px;height: 28px;box-shadow: none;}// 修改激活后的样式::v-deep .el-radio-button__orig-radio:checked+.el-radio-button__inner {background: #373739;border-radius: 2px 2px 2px 2px;border: 1px solid #484849;color: #fff;}}
}.colorInputBody {display: flex;flex-direction: Row;align-items: center;height: 30px;width: 120px;padding-left: 8px;border: 1px solid #000;border-radius: 5px;&-title {padding-left: 8px;color: #000;}
}.colorNoTextBody {width: 30px;height: 30px;border: none;padding: 3px;&-colorBox {width: 24px;height: 24px;border-radius: 4px;}
}.colorBox {width: 26px;height: 14px;
}/* 透明度滑块条 */
.alpha-slider {border-radius: 10px;position: relative;height: 12px;box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAWElEQVRIiWM8fubkfwYygKWJOSM5+mCAhRLNoxaPWjxq8ajFoxbTyeL/DAfJ0Xjs3Cl7Siwmu4Yht1aDgZEYx6MWj1o8avGoxaMWD3qLya5X//4nqx6HAQC7RBGFzolqTAAAAABJRU5ErkJggg==");background-size: 10px 10px;
}/* 滑块 */
.slider {border-radius: 20px;position: absolute;box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);box-sizing: border-box;width: 12px;height: 100%;border: 3px solid #fff;
}
</style>
3.选择器的颜色板,MyColorSelect.vue页面
<template><div class="color-select"><div class="saturation-value" ref="saturation_value" @mousedown="mousedownSV"><div :style="'background-color: hsl(' + hue + ', 100%, 50%);'"><div class="point" :style="pointStyle"></div></div><div class="saturation-value-2"></div><div class="saturation-value-3"></div></div><div class="color-select-middle"><div style="flex: auto"><div class="hue-slider" ref="hue_slider" @mousedown="mousedownHue"><div class="slider" :style="hueSliderStyle"></div></div></div></div></div>
</template><script>
export default {name: "MyColorSelect",props: {color: {type: String,default: "",},alphaValue: {type: Number,default: 100,},},data() {return {pointStyle: "top: 25%; left: 80%;",hueSliderStyle: "left: 0;",hue: 0,saturation: 1,value: 1,red: 255,green: 0,blue: 0,alpha: 1,};},watch: {color: {handler(val) {this.handParse(val);},},alphaValue: {handler(val) {this.$emit("update:color",this.rgba2hex(this.red, this.green, this.blue, this.matchHexA()));},},},mounted() {this.handParse(this.color);},methods: {handParse(color) {if ((this.parseColor(color) ?? "") !== "") {const { r, g, b, a } = this.parseColor(color);this.red = r;this.green = g;this.blue = b;this.alpha = a;this.updateColor();}},updateColor() {let { h, s, v } = this.rgb2hsv(this.red, this.green, this.blue);this.hue = h;this.saturation = s;this.value = v;// 移动背景板圆圈this.pointStyle = `top: ${100 - v * 100}%;left: ${s * 100}%;`;// 移动色调滑块this.hueSliderStyle = `left: ${(this.hue / 360) * 100}%;`;},rgb2hsv(r, g, b) {let r1 = r / 255;let g1 = g / 255;let b1 = b / 255;let cmax = Math.max(r1, g1, b1);let cmin = Math.min(r1, g1, b1);let d = cmax - cmin;let h, s, v;if (d === 0) {h = 0;} else if (cmax === r1) {h = ((60 * (g1 - b1)) / d + 360) % 360;} else if (cmax === g1) {h = 60 * ((b1 - r1) / d + 2);} else if (cmax === b1) {h = 60 * ((r1 - g1) / d + 4);}if (cmax === 0) {s = 0;} else {s = d / cmax;}v = cmax;h = Math.floor(h + 0.5);s = Math.floor(s * 100 + 0.5) / 100;v = Math.floor(v * 100 + 0.5) / 100;return { h, s, v };},// 色调handleChangeHue(e) {let w = this.$refs.hue_slider.clientWidth;let x =e.pageX - this.$refs.saturation_value.getBoundingClientRect().left;x = x < w && x > 0 ? x : x > w ? w : 0;// 计算色调this.hue = Math.floor((x / w) * 360 + 0.5);// hsv转化为rgblet { r, g, b } = this.hsv2rgb(this.hue, this.saturation, this.value);this.red = r;this.green = g;this.blue = b;// 移动滑块this.hueSliderStyle = `left: ${x >= w - 6 ? w - 6 : x}px;`;this.$emit("update:color", this.rgba2hex(r, g, b, this.matchHexA()));},mousedownHue(e) {this.handleChangeHue(e);window.addEventListener("mousemove", this.handleChangeHue);window.addEventListener("mouseup", this.mouseupHue);},mouseupHue(e) {window.removeEventListener("mousemove", this.handleChangeHue);window.removeEventListener("mouseup", this.mouseupHue);},// 饱和度和亮度handleChangeSV(e) {let w = this.$refs.saturation_value.clientWidth;let h = this.$refs.saturation_value.clientHeight;let x =e.pageX - this.$refs.saturation_value.getBoundingClientRect().left;let y = e.pageY - this.$refs.saturation_value.getBoundingClientRect().top;x = x < w && x > 0 ? x : x > w ? w : 0;y = y < h && y > 0 ? y : y > h ? h : 0;// 计算饱和度和亮度this.saturation = Math.floor((x / w) * 100 + 0.5) / 100;this.value = Math.floor((1 - y / h) * 100 + 0.5) / 100;// hsv转化为rgblet { r, g, b } = this.hsv2rgb(this.hue, this.saturation, this.value);this.red = r;this.green = g;this.blue = b;// 移动背景板圆圈this.pointStyle = `top: ${y}px;left: ${x}px;`;this.$emit("update:color", this.rgba2hex(r, g, b, this.matchHexA()));},matchHexA() {let percentage = this.alphaValue * 0.01;return percentage;},mousedownSV(e) {// 鼠标按下计算饱和度和亮度并添加事件this.handleChangeSV(e);// 添加整个页面的鼠标事件window.addEventListener("mousemove", this.handleChangeSV);window.addEventListener("mouseup", this.mouseupSV);},mouseupSV(e) {// 鼠标松开后移除事件window.removeEventListener("mousemove", this.handleChangeSV);window.removeEventListener("mouseup", this.mouseupSV);},parseColor(color) {if (color) {let r, g, b, a;if (typeof color === "string") {if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8}|[0-9a-fA-F]{3}|[0-9a-fA-F]{4})$/.test(color)) {return this.hex2rgba(color);}} else {r = color.r > 255 ? 255 : color.r < 0 ? 0 : color.r;g = color.g > 255 ? 255 : color.g < 0 ? 0 : color.g;b = color.b > 255 ? 255 : color.b < 0 ? 0 : color.b;a = color.a > 1 ? 1 : color.a < 0 ? 0 : color.a;return { r, g, b, a };}} else {return null;}},hsv2rgb(h, s, v) {h === 360 && (h = 0);let i = Math.floor(h / 60) % 6;let f = h / 60 - i;let p = v * (1 - s);let q = v * (1 - s * f);let t = v * (1 - s * (1 - f));let r, g, b;if (i === 0) {r = v;g = t;b = p;} else if (i === 1) {r = q;g = v;b = p;} else if (i === 2) {r = p;g = v;b = t;} else if (i === 3) {r = p;g = q;b = v;} else if (i === 4) {r = t;g = p;b = v;} else if (i === 5) {r = v;g = p;b = q;}r = Math.floor(r * 255 + 0.5);g = Math.floor(g * 255 + 0.5);b = Math.floor(b * 255 + 0.5);return { r, g, b };},rgba2hex(r, g, b, a = 1) {r = parseInt(r);let r1 =r.toString(16).length !== 2 ? "0" + r.toString(16) : r.toString(16);g = parseInt(g);let g1 =g.toString(16).length !== 2 ? "0" + g.toString(16) : g.toString(16);b = parseInt(b);let b1 =b.toString(16).length !== 2 ? "0" + b.toString(16) : b.toString(16);a = parseFloat(a);let a1 = "";if (a !== 1) {let temp = Math.floor(256 * a);a1 =temp.toString(16).length !== 2? "0" + temp.toString(16): temp.toString(16);}return `#${r1}${g1}${b1}${a1}`.toUpperCase();},hex2rgba(s) {if (/^#?[0-9a-fA-F]{3}$/.test(s)) {let b = s.substring(s.length - 1, s.length);let g = s.substring(s.length - 2, s.length - 1);let r = s.substring(s.length - 3, s.length - 2);return hex2rgba(`${r + r}${g + g}${b + b}`);}if (/^#?[0-9a-fA-F]{4}$/.test(s)) {let a = s.substring(s.length - 1, s.length);let b = s.substring(s.length - 2, s.length - 1);let g = s.substring(s.length - 3, s.length - 2);let r = s.substring(s.length - 4, s.length - 3);return hex2rgba(`${r + r}${g + g}${b + b}${a + a}`);}if (/^#?[0-9a-fA-F]{6}$/.test(s)) {let b = parseInt("0x" + s.substring(s.length - 2, s.length));let g = parseInt("0x" + s.substring(s.length - 4, s.length - 2));let r = parseInt("0x" + s.substring(s.length - 6, s.length - 4));return { r, g, b, a: 1 };}if (/^#?[0-9a-fA-F]{8}$/.test(s)) {let a = parseInt("0x" + s.substring(s.length - 2, s.length));a = a / 255;let b = parseInt("0x" + s.substring(s.length - 4, s.length - 2));let g = parseInt("0x" + s.substring(s.length - 6, s.length - 4));let r = parseInt("0x" + s.substring(s.length - 8, s.length - 6));return { r, g, b, a };}},},
};
</script><style scoped>
.color-select {position: relative;user-select: none;width: 100%;padding: 12px 0 0 0;
}/* 饱和度和亮度 */
.saturation-value {cursor: pointer;width: 100%;height: 148px;position: relative;margin-bottom: 12px;box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}.saturation-value>div {position: absolute;top: 0;left: 0;width: 100%;height: 100%;
}/* 圆圈 */
.point {box-sizing: border-box;width: 6px;height: 6px;background-color: transparent;border: 2px solid #ccc;border-radius: 50%;transform: translate(-50%, -50%);position: absolute;z-index: 9;
}.saturation-value-2 {background: linear-gradient(to right, white, #ffffff00);
}.saturation-value-3 {background: linear-gradient(to top, black, #ffffff00);
}/* 色调滑块条 */
.hue-slider {position: relative;height: 10px;background: linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}/* 滑块 */
.slider {position: absolute;box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);box-sizing: border-box;width: 6px;height: 100%;background-color: #fff;
}
</style>
4.其中utils文件夹里的两个文件如下
message.js
import { Message, MessageBox } from 'element-ui';let message = {message: function(str, type = 'success') {Message[type](str);},confirm: function(text, title = '提示', confirm = null, cancel = null) {MessageBox.confirm(text, title, {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then((res) => {confirm && confirm(res);}).catch((res) => {cancel && cancel(res);});}
};export default message;
util.js
//防抖
export const debounce=(fn, t) =>{const delay = t || 100;let timer = null;return function() {const args = arguments;const context = this;if (timer) {clearTimeout(timer);}timer = setTimeout(() => {timer = null;fn.apply(context, args);}, delay);};
}
5.重点:elementStyle.css样式文件,用于更改选择器的覆盖颜色
elementStyle.css文件需要在main.js引入
import '@/assets/css/elementStyle.css'
6.elementStyle.css代码如下
.el-popover{background: #303030 ;color: #ffffff;font-size: 12px;border: 1px solid rgba(255, 255, 255, 0.06);padding: 5px 5px;min-width: 40px;}.popper__arrow {display: none !important;
}
.el-dropdown-menu{background: #303030;border: 1px solid rgba(255, 255, 255, 0.06);
}
.el-dropdown-menu__item {color: #fff;width: 70px;}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover {background: #373739FF;}
7.引入的图片和svg图片在项目源码包里src/assets/image路径下
8.注意点
如果下载源码的话先
先执行
yarn install
再执行
yarn serve
运行成功后直接使用
http://127.0.0.1:8000/home访问