设计思路 | 纯前端实现颜色选择器

在编辑器中,颜色选择器是最常见的组件,UI的设计大同小异,今天来以微信公众号后台为例

可以看到,微信公众平台编辑器中的颜色选择器大致分为四部分:

  • 最近常用颜色
  • 基本色
  • 更多颜色
  • 输入框和确定

常用颜色/基本色

这一部分不必多赘述,循环出方格,背景颜色设置为所需颜色即可

html 复制代码
//最近常用颜色
<ul class="recentCo_ul">
    <li class="recentCo_li recentCo_first" title="清除颜色" @click="handleClearColor"></li>
    <li class="recentCo_li cursor" v-for="(item, index) in recentColorList" :key="index":style="`background:${item}`" :data-color="`${item}`" :title="`${item}`" @click="handleCheckColor">
    </li>
</ul>

最近常用颜色的存储可以接口获取,或者存储在本地缓存中。

颜色模型

在开发之前,需要了解一些基础的颜色模型知识。颜色模型,是用来表示颜色的数学模型,比如常见的RGB,CMYK,HSLHSV等。 目前前端比较常用的是RGBHSL模型,而颜色选择器中大都使用的是HSV模型,因此主要介绍这三种模型。

1、RGB模型

rgb 即红(red)、绿(green)、蓝(blue)三原色模型,前端赋值颜色时使用的rgb(0,0,0)rgba(0,0,0,0.5)#000000black等表示方式都属于rgb模型。

百度百科中显示:

RGB(Red, Green, Blue)颜色模型通常使用于彩色阴极射线管等彩色光栅图形显示设备中,彩色光栅图形的显示器都使用R、G、B数值来驱动R、G、B 电子枪发射电子,并分别激发荧光屏上的R、G、B三种颜色的荧光粉发出不同亮度的光线,并通过相加混合产生各种颜色

因此,颜色选择器中的颜色最终需要转化为rgb/rgba格式或十六进制hex格式供显示器显示出来。

2、HSL模型

HSL是从人的视觉系统出发,用色相H(hue)饱和度S(saturation)亮度L(lightness)来描述色彩。

  • 色相(H): 色彩三要素之一,代表人眼能看到的不同颜色,HSLHSV中的H都代表色相,色相是以60度的间隔排列在圆环上,分别是:360°/0°红、60°黄、120°绿、180°青、240°蓝、300°洋红,在前端处理时,会把圆环处理成长方形的色块,
  • 饱和度(S): 指颜色的纯度,使用0%~100%来衡量,表示色相中颜色成分所占的比例,数值越大,颜色中的灰色越少,颜色越鲜艳,呈现是从灰色到色相颜色的变化。
  • 亮度(L): 表现颜色的明暗程度,使用0%~100%的百分比来度量。反映色彩中混入黑白两色,0%------50%------100%表示黑色------色相------白色的过渡。
3、HSV模型

HSV 采用色相H(hue)饱和度S(saturation)明度V(value)来描述色彩(比如 红色的hsv应该是hsv(0, 100%, 100%) ) 其中色相HSL相同,饱和度和明度有所区别:

  • HSV中的S饱和度,反映色相颜色中混入白色的值,呈现白色到色相(H)颜色的变化;
  • HSL中的S饱和度,反映色相颜色中混入灰色的值,呈现的是一种从灰色到色相(H)颜色的变化。
  • HSV中的V明度,体现的是从黑色到色相(H)颜色的过渡。
  • HSL中的L亮度,体现的是从黑色到色相(H)颜色再到白色的过渡。
4、互相转换

在颜色选择器中,我们主要用到的是rgb十六进制hexHSV的互相转化。

1、rgbhex

js 复制代码
// rgb转十六进制
setRgbTo16(arr) {
   let c = '#';
   for (var i = 0; i < arr.length; i++) {
       var t = Number(arr[i]).toString(16);
       if (Number(arr[i]) < 16) {
           t = '0' + t;
       }
       c += t;
   }
   return c;
}

2、hexrgb

js 复制代码
//十六进制转rgb
set16ToRgb(str) {
   let newStr = (str.toLowerCase()).replace(/\#/g, '')
   let len = newStr.length;
   if (len == 3) {
      let t = ''
      for (var i = 0; i < len; i++) {
          t += newStr.slice(i, i + 1).concat(newStr.slice(i, i + 1))
      }
      newStr = t
    }
    let arr = [];
    for (var i = 0; i < 6; i = i + 2) {
        let s = newStr.slice(i, i + 2)
        arr.push(parseInt("0x" + s))
    }
    return arr
}

3、rgbhsv

js 复制代码
// rgb转hsv
rgbtohsv(arr) {
    var h = 0, s = 0, v = 0;
    var r = arr[0], g = arr[1], b = arr[2];
    arr.sort(function (a, b) {
        return a - b;
    })
    var max = arr[2]
    var min = arr[0];
    v = max / 255;
    if (max === 0) {
       s = 0;
    } else {
       s = 1 - (min / max);
    }
    if (max === min) {
       h = 0;//事实上,max===min的时候,h无论为多少都无所谓
    } else if (max === r && g >= b) {
       h = 60 * ((g - b) / (max - min)) + 0;
    } else if (max === r && g < b) {
       h = 60 * ((g - b) / (max - min)) + 360
    } else if (max === g) {
       h = 60 * ((b - r) / (max - min)) + 120
    } else if (max === b) {
       h = 60 * ((r - g) / (max - min)) + 240
    }
    h = parseInt(h);
    s = parseInt(s * 100);
    v = parseInt(v * 100);
    return [h, s, v]
}

4、hsvrgb

js 复制代码
// hsv转rgb
hsvtorgb(h, s, v) {
   s = s / 100;
   v = v / 100;
   var h1 = Math.floor(h / 60) % 6;
   var f = h / 60 - h1;
   var p = v * (1 - s);
   var q = v * (1 - f * s);
   var t = v * (1 - (1 - f) * s);
   var r, g, b;
   switch (h1) {
       case 0:
         r = v;
         g = t;
         b = p;
       break;
       case 1:
         r = q;
         g = v;
         b = p;
        break;
        case 2:
          r = p;
          g = v;
          b = t;
         break;
         case 3:
           r = p;
           g = q;
           b = v;
         break;
         case 4:
           r = t;
           g = p;
           b = v;
           break;
         case 5:
           r = v;
           g = p;
           b = q;
         break;
    }
    return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}

更多颜色------颜色选择面板区

颜色选择面板相信大家在各种编辑软件中经常使用,右侧是选择色相的滑块,左侧控制其饱和度和明度面板。

1、左侧面板

在各个编辑器中的颜色模型大都使用的HSV模型,通过刚刚学习的颜色模型可知,饱和度S是呈现白色到色相(H)颜色 的变化,明度V是体现的是从黑色到色相(H)颜色 的过渡。这一部分可以使用svg来实现,某个色值通过叠加两个渐变图层,一个是白色到色相的渐变,一个是黑色到色相的过渡。

图2为去掉黑色渐变,图3为去掉白色渐变 。可以看到:白色渐变是从左向右的(饱和度),黑色渐变是从下至上的(明度),两者重叠即为图1的效果。

html 复制代码
<svg id="back_svg">
     <rect x="0" y="0" width="100%" height="100%" :fill="`url(#gradient-white${pickId})`"></rect>
     <rect x="0" y="0" width="100%" height="100%" :fill="`url(#gradient-black${pickId})`"></rect>
     <defs>
        <linearGradient :id="`gradient-black${pickId}`" x1="0%" y1="100%" x2="0%" y2="0%">
            <stop offset="0%" stop-color="#000000" stop-opacity="1"></stop>
            <stop offset="100%":stop-color="`rgb(${curSliderColor[0]},${curSliderColor[1]},${curSliderColor[2]})`" stop-opacity="0"></stop>
        </linearGradient>
        <linearGradient :id="`gradient-white${pickId}`" x1="0%" y1="100%" x2="100%" y2="100%">
            <stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"></stop>
            <stop offset="100%" :stop-color="`rgb(${curSliderColor[0]},${curSliderColor[1]},${curSliderColor[2]})`" stop-opacity="0"></stop>
        </linearGradient>
    </defs>
</svg>

其中,我们在defs中定义渐变颜色,通过url(# )赋值到两个rect中,<linearGradient>标签可以用来定义渐变元素,x1/y1/x2/y2来定义渐变的起始坐标,每个渐变的色值写在<stop>中,其中stop-color代表颜色,offset表示该颜色的位置百分比。

鼠标点击位置色值

当鼠标点击某个位置时,可以获取到鼠标位置XY,因此,此时颜色的HSVH为右侧选中的色相值,S是鼠标位置在面板宽度所占的百分比,即s=x/面板宽度*100V是鼠标位置在面板高度中所占的百分比,即v=y/面板高度*100,可以得到当前鼠标点击位置颜色的hsv,再转为rgb格式即可。

html 复制代码
<div class="colorBack" @mousedown="colorBarDown" @mousemove="colorBarMove" @mouseup="colorBarUp" @mouseleave="colorBarUp" :style="`background:rgb(${curSliderColor[0]},${curSliderColor[1]},${curSliderColor[2]})`">
          ...//上方svg面板 
          <div class="colorBar colorBarTarget" :class="`colorBarTarget_${pickId}`" :style="`top:${colorBarTop}px;left:${colorBarLeft}px`">
             <div class="colorBarTarget" :class="`colorBarTarget_${pickId}`"></div>
          </div>//鼠标滑块
</div>
js 复制代码
//计算当前坐标点的hsv并转化为rgb格式
setColor(x, y) {
    this.colorBarTop = y - 4;//由于定位原因,因此获取到的坐标需要减去外间距
    this.colorBarLeft = x - 4;
    this.Sval = x / 185 * 100;//计算s的值
    this.Vval = (1 - y / 150) * 100;//计算v的值
    this.curColor = this.hsvtorgb(this.Hval, this.Sval, this.Vval)//h是右侧滑块选中的色相
    this.colorInput = this.setRgbTo16(this.curColor);
},
2、右侧滑块

这里的滑块就是色相环展开,因此只需要一条渐变即可

html 复制代码
<svg id="hsv_svg">
    <rect x="0" y="0" width="100%" height="100%" :fill="`url(#gradient-hsv${pickId})`"></rect>
    <linearGradient :id="`gradient-hsv${pickId}`" x1="0%" y1="100%" x2="0%" y2="0%">
        <stop offset="0%" stop-color="#FF0000" stop-opacity="1"></stop>
        <stop offset="13%" stop-color="#FF00FF" stop-opacity="1"></stop>
        <stop offset="25%" stop-color="#8000FF" stop-opacity="1"></stop>
        <stop offset="38%" stop-color="#0040FF" stop-opacity="1"></stop>
        <stop offset="50%" stop-color="#00FFFF" stop-opacity="1"></stop>
        <stop offset="63%" stop-color="#00FF40" stop-opacity="1"></stop>
        <stop offset="75%" stop-color="#0BED00" stop-opacity="1"></stop>
        <stop offset="88%" stop-color="#FFFF00" stop-opacity="1"></stop>
        <stop offset="100%" stop-color="#FF0000" stop-opacity="1"></stop>
   </linearGradient>
</svg>

色相滑块

由上方颜色模型可知,色相条即是将色相环变为长方形,起始位置和结束位置都是红色,获取滑块选中位置的hsv,依旧可以看成是鼠标点击位置的色值,此时饱和度S明度V都为100,只需要考虑色相H的值,h=鼠标Y/色相条高度*360

html 复制代码
<div class="colorSilder" ref="slider" @mousedown="silderBarDown" @mousemove="silderBarMove" @mouseup="sliderBarUp" @mouseleave="sliderBarUp">
    ...//svg渐变              
    <div class="silderBar" :class="`silderBar_${pickId}`" :style="`top:${siderBarTop}px`"></div>//鼠标滑块
</div>
js 复制代码
setSlilderColor(y) {
   this.siderBarTop = y - 3;
   this.offsetY = y / 150;
   this.Hval = 360 * this.offsetY;//计算h的值
   this.curColor = this.hsvtorgb(this.Hval, this.Sval, this.Vval)//s和v都是100
   this.curSliderColor = this.curColor;
   this.colorInput = this.setRgbTo16(this.curColor);
},

综上,我们可以取到所选颜色的hsv值,并通过互转方法转化为rgb16进制值,用于前端展示和输入框回显。

颜色回显

在输入框中输入的色值需要同步回显至面板中,只需要将获取到的十六进制色值转为hsv,再反向计算出滑块位置即可

html 复制代码
<el-input class v-model="colorInput" @input="handleInputChange"></el-input>
js 复制代码
// input修改时回显色盘
handleInputChange(value){
    var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
    if (reg.test(value)) {
       this.curColor = this.set16ToRgb(value);
       this.colorInputHsv = this.rgbtohsv(this.curColor)
       this.curSliderColor= this.curColor;
       this.Hval = this.colorInputHsv[0];
       this.Sval = this.colorInputHsv[1];
       this.Vval = this.colorInputHsv[2];
       this.siderBarTop=(this.Hval*15)/36-3;
       this.colorBarLeft=(185*this.Sval)/100-4;
       this.colorBarTop=(1-(this.Vval/100))*150-4;
     }
},

封装组件

最后,我们将其封装为组件(以下代码以Vue为例)

html 复制代码
 <div class="colorPicker">
        <el-popover placement="bottom" popperClass="colorPopper" :ref="`popoverRef_${pickId}`" width="240" trigger="click"
            @show="popoverShow">
            <div class="color_content">
                <span class="color_title">最近使用颜色</span>
                <ul class="recentCo_ul">
                    <li class="recentCo_li recentCo_first" title="清除颜色" @click="handleClearColor"></li>
                    <li class="recentCo_li cursor" v-for="(item, index) in recentColorList" :key="index"
                        :style="`background:${item}`" :data-color="`${item}`" :title="`${item}`" @click="handleCheckColor">

                    </li>
                </ul>
                <ul class="color_tab">
                    <li class="colorTab_li" :class="activeTab == index ? '-activeTab' : ''"
                        @click="handleActiveTabChange(index)" v-for="(item, index) in colorTabList" :key="index">{{ item
                        }}</li>
                </ul>
                <table v-show="activeTab == 0" class="edui-box ue_colortable edui-default colorTable"
                    style="border-collapse: collapse;" cellspacing="0" cellpadding="0">
                    <tbody class="edui-default">
                        <tr class="edui-default"
                            :class="{ 'edui-colorpicker-tablefirstrow': index == 0 || index == colorList.length - 1 }"
                            v-for="(item, index) in colorList" :key="index">
                            <td class="edui-default pr-4" v-for="(itemIn, indexIn) in item" :key="indexIn">
                                <a hidefocus="" :title="itemIn" onclick="return false;" href="javascript:" unselectable="on"
                                    class="edui-box edui-colorpicker-colorcell edui-default"
                                    :class="index == 0 || index == colorList.length - 1 || index == colorList.length - 2 ? 'isFirst' : 'noFirst'"
                                    :data-color="`${itemIn}`" :style="`background:${itemIn};`" @click="handleCheckColor">
                                </a>
                            </td>
                        </tr>
                        <tr></tr>
                    </tbody>
                </table>
                <div class="picker_svg" v-show="activeTab == 1">
                    <div class="colorBack" @mousedown="colorBarDown" @mousemove="colorBarMove" @mouseup="colorBarUp"
                        @mouseleave="colorBarUp"
                        :style="`background:rgb(${curSliderColor[0]},${curSliderColor[1]},${curSliderColor[2]})`">
                        <svg id="back_svg">
                            <rect x="0" y="0" width="100%" height="100%" :fill="`url(#gradient-white${pickId})`"></rect>
                            <rect x="0" y="0" width="100%" height="100%" :fill="`url(#gradient-black${pickId})`"></rect>
                            <defs>
                                <linearGradient :id="`gradient-black${pickId}`" x1="0%" y1="100%" x2="0%" y2="0%">
                                    <stop offset="0%" stop-color="#000000" stop-opacity="1"></stop>
                                    <stop offset="100%"
                                        :stop-color="`rgb(${curSliderColor[0]},${curSliderColor[1]},${curSliderColor[2]})`"
                                        stop-opacity="0"></stop>
                                </linearGradient>
                                <linearGradient :id="`gradient-white${pickId}`" x1="0%" y1="100%" x2="100%" y2="100%">
                                    <stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"></stop>
                                    <stop offset="100%"
                                        :stop-color="`rgb(${curSliderColor[0]},${curSliderColor[1]},${curSliderColor[2]})`"
                                        stop-opacity="0"></stop>
                                </linearGradient>
                            </defs>
                        </svg>
                        <div class="colorBar colorBarTarget" :class="`colorBarTarget_${pickId}`"
                            :style="`top:${colorBarTop}px;left:${colorBarLeft}px`">
                            <div class="colorBarTarget" :class="`colorBarTarget_${pickId}`"></div>
                        </div>
                    </div>
                    <div class="colorSilder" ref="slider" @mousedown="silderBarDown" @mousemove="silderBarMove"
                        @mouseup="sliderBarUp" @mouseleave="sliderBarUp">
                        <svg id="hsv_svg">
                            <rect x="0" y="0" width="100%" height="100%" :fill="`url(#gradient-hsv${pickId})`"></rect>
                            <linearGradient :id="`gradient-hsv${pickId}`" x1="0%" y1="100%" x2="0%" y2="0%">
                                <stop offset="0%" stop-color="#FF0000" stop-opacity="1"></stop>
                                <stop offset="13%" stop-color="#FF00FF" stop-opacity="1"></stop>
                                <stop offset="25%" stop-color="#8000FF" stop-opacity="1"></stop>
                                <stop offset="38%" stop-color="#0040FF" stop-opacity="1"></stop>
                                <stop offset="50%" stop-color="#00FFFF" stop-opacity="1"></stop>
                                <stop offset="63%" stop-color="#00FF40" stop-opacity="1"></stop>
                                <stop offset="75%" stop-color="#0BED00" stop-opacity="1"></stop>
                                <stop offset="88%" stop-color="#FFFF00" stop-opacity="1"></stop>
                                <stop offset="100%" stop-color="#FF0000" stop-opacity="1"></stop>
                            </linearGradient>
                        </svg>
                        <div class="silderBar" :class="`silderBar_${pickId}`" :style="`top:${siderBarTop}px`"></div>
                    </div>
                </div>
                <div class="colorPick_bottom">
                    <div class="color_div" :style="`background:${colorInput}`"></div>
                    <div class="color_input"><el-input class v-model="colorInput" @input="handleInputChange"></el-input></div>
                    <button class="color_btn" @click="handleConfirmColor">确定</button>
                </div>

            </div>
            <div slot="reference">
                <i class="iconfont iconStyle" :class="iconClass" :title="iconTitle"></i>
            </div>
        </el-popover>
    </div>
js 复制代码
var isFirst = true;
export default {
    name: 'colorPicker',
    data() {
        return {
            pickId: '',
            colorTabList: ['基本颜色', '更多颜色'],
            activeTab: 0,
            recentColorList: ['#548dd4', '#366092', '#000'],
            colorList: [
                ['#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646'],
                ['#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada'],
                ['#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5'],
                ['#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#92cddc', '#fac08f'],
                ['#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#31859b', '#e36c09'],
                ['#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#205867', '#974806'],
                ['#c00000', '#ff0000', '#ffc000', '#ffff00', '#92d050', '#00b050', '#00b0f0', '#0070c0', '#002060', '#7030a0'],
            ],
            colorInput: '#555',
            colorInputRgb: [85, 85, 85],
            colorInputHsv: [],
            colorBgState: false,
            colorBarTop: 0,
            colorBarLeft: 0,
            sliderState: false,
            startY: 0,
            offsetY: 0,
            Hval: 0,
            Sval: 100,
            Vval: 100,
            siderBarTop: 0,
            curColor: [255, 0, 0],
            curSliderColor: [255, 0, 0],
        }
    },
    methods: {
        popoverShow() {
            this.recentColorList = localStorage.getItem('recentColor').split(',');
        },
        handleActiveTabChange(index) {
            this.activeTab = index;

        },
        debounce(fn, wait = 200) {
            let timer = null;
            return function (...args) {

                if (isFirst) {
                    fn.apply(this, args)
                    isFirst = false
                } else {
                    if (timer) {
                        clearTimeout(timer)
                        timer = null
                    }
                    timer = setTimeout(function () {
                        fn.apply(this, args)
                    }, wait)
                }

            }
        },
        // slider 事件
        silderBarDown(e) {
            this.sliderState = true;
            this.Sval = 100;
            this.Vval = 100;
            if (e.target != $(`.silderBar_${this.pickId}`)[0]) {
                this.setSlilderColor(e.offsetY)
            }

        },
        silderBarMove(e) {
            if (!this.sliderState) return;
            this.debounce(() => {
                if (e.target != $(`.silderBar_${this.pickId}`)[0]) {
                    this.setSlilderColor(e.offsetY)
                }
            }, 200)()
        },
        sliderBarUp() {
            this.sliderState = false;
            isFirst = true;

        },
        setSlilderColor(y) {
            this.siderBarTop = y - 3;
            this.offsetY = y / 150;
            this.Hval = 360 * this.offsetY;
            this.curColor = this.hsvtorgb(this.Hval, this.Sval, this.Vval)
            this.curSliderColor = this.curColor;
            this.colorInput = this.setRgbTo16(this.curColor);
        },
        colorBarDown(e) {
            this.colorBgState = true;
            if (e.target != $(`.colorBarTarget_${this.pickId}`)[0] && e.target != $(`.colorBarTarget_${this.pickId}`)[1]) {
                this.setColor(e.offsetX, e.offsetY)
            }

        },
        colorBarMove(e) {
            if (!this.colorBgState) return;
            this.debounce(() => {
                if (e.target != $(`.colorBarTarget_${this.pickId}`)[0] && e.target != $(`.colorBarTarget_${this.pickId}`)[1]) {
                    this.setColor(e.offsetX, e.offsetY)
                }
            }, 200)()

        },
        colorBarUp() {
            this.colorBgState = false;
            isFirst = true;
        },
        setColor(x, y) {
            this.colorBarTop = y - 4;
            this.colorBarLeft = x - 4;
            this.Sval = x / 185 * 100;
            this.Vval = (1 - y / 150) * 100;
            this.curColor = this.hsvtorgb(this.Hval, this.Sval, this.Vval)
            this.colorInput = this.setRgbTo16(this.curColor);
        },
        // 清空color
        handleClearColor() {
            this.$emit('changeColor', '');
            this.$refs[`popoverRef_${this.pickId}`].doClose();
        },
        // 选择color
        handleCheckColor(e) {
            let color = e.currentTarget.dataset.color
            this.handleSubmitColor(color)
        },
        handleConfirmColor() {
            var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
            if (reg.test(this.colorInput)) {
                this.handleSubmitColor(this.colorInput)
            }
        },
        // 修改颜色
        handleSubmitColor(val) {
            this.recentColorList.unshift(val);
            this.recentColorList = Array.from(new Set(this.recentColorList));
            if (this.recentColorList.length > 8) {
                this.recentColorList = this.recentColorList.slice(0, 8)
            }
            localStorage.setItem('recentColor', this.recentColorList)
            this.$emit('changeColor', val);
            this.$refs[`popoverRef_${this.pickId}`].doClose();
        },
        // input修改时回显色盘
        handleInputChange(value){
            console.log(value)
            var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
            if (reg.test(value)) {
                this.curColor = this.set16ToRgb(value);
                this.colorInputHsv = this.rgbtohsv(this.curColor)
                this.curSliderColor= this.curColor;
                this.Hval = this.colorInputHsv[0];
                this.Sval = this.colorInputHsv[1];
                this.Vval = this.colorInputHsv[2];
                this.siderBarTop=(this.Hval*15)/36-3;
                this.colorBarLeft=(185*this.Sval)/100-4;
                this.colorBarTop=(1-(this.Vval/100))*150-4;
            }

        },
        // hsv转rgb
        hsvtorgb(h, s, v) {
            s = s / 100;
            v = v / 100;
            var h1 = Math.floor(h / 60) % 6;
            var f = h / 60 - h1;
            var p = v * (1 - s);
            var q = v * (1 - f * s);
            var t = v * (1 - (1 - f) * s);
            var r, g, b;
            switch (h1) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;
                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;
                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;
                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;
                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;
                case 5:
                    r = v;
                    g = p;
                    b = q;
                    break;
            }
            return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
        },
        // rgb转hsv
        rgbtohsv(arr) {
            var h = 0, s = 0, v = 0;
            var r = arr[0], g = arr[1], b = arr[2];
            arr.sort(function (a, b) {
                return a - b;
            })
            var max = arr[2]
            var min = arr[0];
            v = max / 255;
            if (max === 0) {
                s = 0;
            } else {
                s = 1 - (min / max);
            }
            if (max === min) {
                h = 0;//事实上,max===min的时候,h无论为多少都无所谓
            } else if (max === r && g >= b) {
                h = 60 * ((g - b) / (max - min)) + 0;
            } else if (max === r && g < b) {
                h = 60 * ((g - b) / (max - min)) + 360
            } else if (max === g) {
                h = 60 * ((b - r) / (max - min)) + 120
            } else if (max === b) {
                h = 60 * ((r - g) / (max - min)) + 240
            }
            h = parseInt(h);
            s = parseInt(s * 100);
            v = parseInt(v * 100);
            return [h, s, v]
        },

        //十六进制转rgb
        set16ToRgb(str) {
            // var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
            // if (!reg.test(str)) { return; }
            let newStr = (str.toLowerCase()).replace(/\#/g, '')
            let len = newStr.length;
            if (len == 3) {
                let t = ''
                for (var i = 0; i < len; i++) {
                    t += newStr.slice(i, i + 1).concat(newStr.slice(i, i + 1))
                }
                newStr = t
            }
            let arr = [];
            for (var i = 0; i < 6; i = i + 2) {
                let s = newStr.slice(i, i + 2)
                arr.push(parseInt("0x" + s))
            }
            return arr
        },
        // rgb转十六进制
        setRgbTo16(arr) {
            let c = '#';
            for (var i = 0; i < arr.length; i++) {
                var t = Number(arr[i]).toString(16);
                if (Number(arr[i]) < 16) {
                    t = '0' + t;
                }
                c += t;
            }
            return c;
        },

    },
    computed: {},
    created() {
        this.pickId = Math.random().toString(36).slice(-10);
    },
    watch: {},
    mounted() {

    },
    props: {
        iconClass: {
            type: String,
            default: 'iconzitiyanse'
        },
        iconTitle:{
            type:String,
            default:'颜色'
        }
    },
}
css 复制代码
相关推荐
叫我菜菜就好31 分钟前
【Flutter_Web】Flutter编译Web第三篇(网络请求篇):dio如何改造方法,变成web之后数据如何处理
前端·网络·flutter
NoneCoder37 分钟前
CSS系列(26)-- 动画性能优化详解
前端·css·性能优化
滚雪球~37 分钟前
@vue/cli启动异常:ENOENT: no such file or directory, scandir
前端·javascript·vue.js
GDAL1 小时前
vue3入门教程:ref函数
前端·vue.js·elementui
GISer_Jing1 小时前
Vue3状态管理——Pinia
前端·javascript·vue.js
萧寂1731 小时前
ios底部小横条高度适配
css
好开心331 小时前
axios的使用
开发语言·前端·javascript·前端框架·html
Domain-zhuo1 小时前
Git常用命令
前端·git·gitee·github·gitea·gitcode
菜根Sec2 小时前
XSS跨站脚本攻击漏洞练习
前端·xss
m0_748257182 小时前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端