基于vue3的取色器

最近项目需要一个取色器功能,基于此写了一个取色器组件。

组件支持:rgb、rgba、hex6、hex8、hsv格式的色值格式。

组件结构:

  • 取色盘
  • 色调选择器
  • 透明度选择器
  • 可修改色值区
  • 预设颜色盘

1. 取色盘

取色盘区域通过HSL色相、饱和度和亮度三个参数展示取色范围

对取色盘添加鼠标事件(mousedown、mousemove、mouseup)指定当前在颜色盘中的位置

function mousedownColorPalette(e) {
  // 鼠标按下计算饱和度和亮度并添加事件
  handleChangeColorPalette(e)
  // 添加整个页面的鼠标事件
  window.addEventListener('mousemove', handleChangeColorPalette)
  window.addEventListener('mouseup', mouseupColorPalette)
}

function mouseupColorPalette(e) {
  // 鼠标松开后移除事件
  window.removeEventListener('mousemove', handleChangeColorPalette)
  window.removeEventListener('mouseup', mouseupColorPalette)
}

通过当前颜色盘位置计算当前选中位置的颜色值

// 计算选中点的颜色值
function handleChangeColorPalette(e) {
  let w = saturation_value.value.clientWidth
  let h = saturation_value.value.clientHeight
  let x = e.pageX - saturation_value.value.getBoundingClientRect().left
  let y = e.pageY - saturation_value.value.getBoundingClientRect().top
  x = x < w && x > 0 ? x : x > w ? w : 0
  y = y < h && y > 0 ? y : y > h ? h : 0
  // 计算饱和度和亮度
  saturation.value = Math.floor((x / w) * 100 + 0.5) / 100
  value.value = Math.floor((1 - y / h) * 100 + 0.5) / 100
  // hsv转化为rgb
  let { r, g, b } = hsv2rgb(hue.value, saturation.value, value.value)
  red.value = r
  green.value = g
  blue.value = b
  // 移动背景板圆圈
  pointStyle.value = `top: ${y}px;left: ${x}px;`
}

2. 色调选择器

滑动色调选择器滑块调整当前选择选取的颜色值,也可调整当前颜色选取之后的透明度

对选择器添加鼠标事件(mousedown、mousemove、mouseup)调整滑块位置

  function mousedownHue(e) {
    handleChangeHue(e)
    window.addEventListener('mousemove', handleChangeHue)
    window.addEventListener('mouseup', mouseupHue)
  }

  function mouseupHue(e) {
    window.removeEventListener('mousemove', handleChangeHue)
    window.removeEventListener('mouseup', mouseupHue)
  }
  function mousedownAlpha(e) {
    handleChangeAlpha(e)
    window.addEventListener('mousemove', handleChangeAlpha)
    window.addEventListener('mouseup', mouseupAlpha)
  }

  function mouseupAlpha(e) {
    window.removeEventListener('mousemove', handleChangeAlpha)
    window.removeEventListener('mouseup', mouseupAlpha)
  }

 通过滑块位置计算当前色值与透明度

  // 色调
  function handleChangeHue(e) {
    let w = hue_slider.value.clientWidth
    let x = e.pageX - saturation_value.value.getBoundingClientRect().left
    x = x < w && x > 0 ? x : x > w ? w : 0
    // 计算色调
    hue.value = Math.floor((x / w) * 360 + 0.5)
    // hsv转化为rgb
    let { r, g, b } = hsv2rgb(hue.value, saturation.value, value.value)
    red.value = r
    green.value = g
    blue.value = b
    // 移动滑块
    hueSliderStyle.value = `left: ${x >= w - 6 ? w - 6 : x}px;`
  }
  // 透明度
  function handleChangeAlpha(e) {
    let w = alpha_slider.value.clientWidth
    let x = e.pageX - saturation_value.value.getBoundingClientRect().left
    x = x < w && x > 0 ? x : x > w ? w : 0
    // 计算透明度
    alpha.value = Math.floor((x / w) * 100 + 0.5) / 100
    // 移动滑块
    alphaSliderStyle.value = `left: ${x >= w - 6 ? w - 6 : x}px;`
  }

 3.可修改色值区

可编辑hex、rgba来手动调整当前组件的色值,相关逻辑如下:

  // 输入框值变化,限制输入的值
  function hexChange(e) {
    let v = e.target.value
    if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(v)) {
      let { r, g, b, a } = hex2rgba(v)
      red.value = r
      green.value = g
      blue.value = b
      alpha.value = a
    }
  }

  function redChange(e) {
    let v = e.target.value
    if (v !== '') {
      v > 255 && (red.value = 255)
      v < 0 && (red.value = 0)
      v >= 0 && v <= 255 && (red.value = parseInt(v))
    }
  }

  function greenChange(e) {
    let v = e.target.value
    if (v !== '') {
      v > 255 && (green.value = 255)
      v < 0 && (green.value = 0)
      v >= 0 && v <= 255 && (green.value = parseInt(v))
    }
  }

  function blueChange(e) {
    let v = e.target.value
    if (v !== '') {
      v > 255 && (blue.value = 255)
      v < 0 && (blue.value = 0)
      v >= 0 && v <= 255 && (blue.value = parseInt(v))
    }
  }

  function alphaChange(e) {
    let v = e.target.value
    if (v !== '') {
      v = parseFloat(v)
      alpha.value = v
      v > 1 && (alpha.value = 1)
      v < 0 && (alpha.value = 0)
      v >= 0 && v <= 1 && (alpha.value = v)
    }
  }

4.预设颜色盘

可通过预先设置的颜色只来快捷显示、选中对应的色值

  // 点击预设方块事件
  function predefineChange(item) {
    if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(item)) {
      let { r, g, b, a } = hex2rgba(item)
      red.value = r
      green.value = g
      blue.value = b
      alpha.value = a
    }
  }

注意:

当前组件仅为展示组件,如果需要适应项目中不同的业务需求(例如:将取色器放在气泡卡片中...),还需进行二次封装。

API:

属性名说明类型默认值

color

当前组件传入的色值string--

predefine

预设颜色string[][]

alpha

是否开启透明度booleanfalse

mode

色值格式(hex6/hex8/rgb/rgba)stringhex6

完整代码如下:

  <div class="color-select">
    <div class="saturation-value" ref="saturation_value" @mousedown="mousedownColorPalette">
      <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 class="color-slider">
        <div class="hue-slider slider-item" ref="hue_slider" @mousedown="mousedownHue">
          <div class="slider" :style="hueSliderStyle"></div>
        </div>
        <div class="alpha-slider slider-item" ref="alpha_slider" @mousedown="mousedownAlpha" v-if="props.alpha">
          <div class="slider" :style="alphaSliderStyle"></div>
          <div
            :style="`background: linear-gradient(to right, rgba(0,0,0,0), ${colorEnums.rgb});width: 100%;height: 100%`"
          ></div>
        </div>
      </div>
      <div class="color-diamond">
        <div
          :style="`background-color: ${colorEnums.rgba};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>
    </div>
    <div class="color-value">
      <div class="hex">
        <label>
          <input :value="colorEnums.hex8" @input="hexChange" spellcheck="false" />
        </label>
        <p>Hex</p>
      </div>
      <div class="rgba-r">
        <label>
          <input :value="red" @input="redChange" />
        </label>
        <p>R</p>
      </div>
      <div class="rgba-g">
        <label>
          <input :value="green" @input="greenChange" />
        </label>
        <p>G</p>
      </div>
      <div class="rgba-b">
        <label>
          <input :value="blue" @input="blueChange" />
        </label>
        <p>B</p>
      </div>
      <div class="rgba-a" v-if="props.alpha">
        <label>
          <input :value="alpha" @input="alphaChange" />
        </label>
        <p>A</p>
      </div>
    </div>
    <ul class="predefine">
      <li
        class="predefine-item"
        v-for="item in predefine"
        :key="item"
        :style="`background-color: ${item}`"
        @click="predefineChange(item)"
      ></li>
    </ul>
    <div class="color-actions">
      <span class="cancel" @click="emits('close')">取消</span>
      <span class="confirm" @click="handleConfirm">确定</span>
    </div>
  </div>
  import { ref, computed, watch, onMounted } from 'vue'

  const props = defineProps({
    color: {
      type: Object || String,
      default() {
        return {
          r: 217,
          g: 128,
          b: 95,
          a: 1
        }
      }
    },
    predefine: {
      type: Array,
      default() {
        return []
      }
    },
    alpha: {
      type: Boolean,
      default: true
    },
    mode: {
      type: String,
      default: 'hex6' // hex6/hex8/rgb/rgba
    }
  })

  const emits = defineEmits(['update:color', 'close'])

  const saturation_value = ref(null)
  const hue_slider = ref(null)
  const alpha_slider = ref(null)

  let pointStyle = ref('top: 25%;left: 80%;')
  let hueSliderStyle = ref('left: 0;')
  let alphaSliderStyle = ref('left: calc(100% - 6px);')

  let hue = ref(0)
  let saturation = ref(1)
  let value = ref(1)

  let red = ref(255)
  let green = ref(0)
  let blue = ref(0)

  let alpha = ref(1)

  onMounted(() => {
    console.log('parseColor(props.color)', parseColor(props.color))

    let { r, g, b, a } = parseColor(props.color)
    red.value = r
    green.value = g
    blue.value = b
    alpha.value = a
  })

  watch([red, green, blue], () => {
    let { h, s, v } = rgb2hsv(red.value, green.value, blue.value)

    hue.value = h
    saturation.value = s
    value.value = v

    // 移动背景板圆圈
    pointStyle.value = `top: ${100 - v * 100}%;left: ${s * 100}%;`
    // 移动色调滑块
    hueSliderStyle.value = `left: ${(hue.value / 360) * 100}%;`
  })

  watch(alpha, () => {
    // 移动透明度滑块
    alphaSliderStyle.value = `left: ${alpha.value >= 1 ? 'calc(100% - 6px)' : alpha.value * 100 + '%'};`
  })

  let colorEnums = computed(() => {
    let r = red.value
    let g = green.value
    let b = blue.value
    let a = alpha.value
    let h = hue.value
    let s = saturation.value
    let v = value.value
    return {
      rgb: `rgba(${r},${g},${b})`,
      rgba: `rgba(${r},${g},${b},${a})`,
      hex6: rgba2hex(r, g, b),
      hex8: rgba2hex(r, g, b, a),
      hsv: `hsv(${h},${s},${v})`
    }
  })

  // 确认选中的颜色值
  const handleConfirm = () => {
    console.log('props.mode', props.mode)
    console.log('handleConfirm', (colorEnums.value as any)[props.mode])
    emits('update:color', (colorEnums.value as any)[props.mode])
  }

  // 输入框值变化,限制输入的值
  function hexChange(e) {
    let v = e.target.value
    if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(v)) {
      let { r, g, b, a } = hex2rgba(v)
      red.value = r
      green.value = g
      blue.value = b
      alpha.value = a
    }
  }

  function redChange(e) {
    let v = e.target.value
    if (v !== '') {
      v > 255 && (red.value = 255)
      v < 0 && (red.value = 0)
      v >= 0 && v <= 255 && (red.value = parseInt(v))
    }
  }

  function greenChange(e) {
    let v = e.target.value
    if (v !== '') {
      v > 255 && (green.value = 255)
      v < 0 && (green.value = 0)
      v >= 0 && v <= 255 && (green.value = parseInt(v))
    }
  }

  function blueChange(e) {
    let v = e.target.value
    if (v !== '') {
      v > 255 && (blue.value = 255)
      v < 0 && (blue.value = 0)
      v >= 0 && v <= 255 && (blue.value = parseInt(v))
    }
  }

  function alphaChange(e) {
    let v = e.target.value
    if (v !== '') {
      v = parseFloat(v)
      alpha.value = v
      v > 1 && (alpha.value = 1)
      v < 0 && (alpha.value = 0)
      v >= 0 && v <= 1 && (alpha.value = v)
    }
  }

  // 点击预设方块事件
  function predefineChange(item) {
    if (/^#?([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(item)) {
      let { r, g, b, a } = hex2rgba(item)
      red.value = r
      green.value = g
      blue.value = b
      alpha.value = a
    }
  }

  // 计算选中点的颜色值
  function handleChangeColorPalette(e) {
    let w = saturation_value.value.clientWidth
    let h = saturation_value.value.clientHeight
    let x = e.pageX - saturation_value.value.getBoundingClientRect().left
    let y = e.pageY - saturation_value.value.getBoundingClientRect().top
    x = x < w && x > 0 ? x : x > w ? w : 0
    y = y < h && y > 0 ? y : y > h ? h : 0
    // 计算饱和度和亮度
    saturation.value = Math.floor((x / w) * 100 + 0.5) / 100
    value.value = Math.floor((1 - y / h) * 100 + 0.5) / 100
    // hsv转化为rgb
    let { r, g, b } = hsv2rgb(hue.value, saturation.value, value.value)
    red.value = r
    green.value = g
    blue.value = b
    // 移动背景板圆圈
    pointStyle.value = `top: ${y}px;left: ${x}px;`
  }

  function mousedownColorPalette(e) {
    // 鼠标按下计算饱和度和亮度并添加事件
    handleChangeColorPalette(e)
    // 添加整个页面的鼠标事件
    window.addEventListener('mousemove', handleChangeColorPalette)
    window.addEventListener('mouseup', mouseupColorPalette)
  }

  function mouseupColorPalette(e) {
    // 鼠标松开后移除事件
    window.removeEventListener('mousemove', handleChangeColorPalette)
    window.removeEventListener('mouseup', mouseupColorPalette)
  }

  // 色调
  function handleChangeHue(e) {
    let w = hue_slider.value.clientWidth
    let x = e.pageX - saturation_value.value.getBoundingClientRect().left
    x = x < w && x > 0 ? x : x > w ? w : 0
    // 计算色调
    hue.value = Math.floor((x / w) * 360 + 0.5)
    // hsv转化为rgb
    let { r, g, b } = hsv2rgb(hue.value, saturation.value, value.value)
    red.value = r
    green.value = g
    blue.value = b
    // 移动滑块
    hueSliderStyle.value = `left: ${x >= w - 6 ? w - 6 : x}px;`
  }

  function mousedownHue(e) {
    handleChangeHue(e)
    window.addEventListener('mousemove', handleChangeHue)
    window.addEventListener('mouseup', mouseupHue)
  }

  function mouseupHue(e) {
    window.removeEventListener('mousemove', handleChangeHue)
    window.removeEventListener('mouseup', mouseupHue)
  }

  // 透明度
  function handleChangeAlpha(e) {
    let w = alpha_slider.value.clientWidth
    let x = e.pageX - saturation_value.value.getBoundingClientRect().left
    x = x < w && x > 0 ? x : x > w ? w : 0
    // 计算透明度
    alpha.value = Math.floor((x / w) * 100 + 0.5) / 100
    // 移动滑块
    alphaSliderStyle.value = `left: ${x >= w - 6 ? w - 6 : x}px;`
  }

  function mousedownAlpha(e) {
    handleChangeAlpha(e)
    window.addEventListener('mousemove', handleChangeAlpha)
    window.addEventListener('mouseup', mouseupAlpha)
  }

  function mouseupAlpha(e) {
    window.removeEventListener('mousemove', handleChangeAlpha)
    window.removeEventListener('mouseup', mouseupAlpha)
  }

  /**
   * 解析输入的数据,只能解析hex颜色和rgb对象形式的数据
   * @param color
   */
  function 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 hex2rgba(color)
        } else if (color.includes('linear-gradient')) {
          console.log('111parseColor111', color)
          let matchColors = color.match(/#[0-9a-fA-F]{6}/g)
          console.log('matchColors', matchColors)
          let avgColor = getAvgColor(matchColors)
          console.log('avgColor', avgColor)
          return hex2rgba(avgColor)
        }
      } 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
    }
  }

  function 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 }
  }

  function 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 }
  }

  function 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()
  }

  function hex2rgba(s) {
    console.log('111111', 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 }
    }
  }

  function getAvgColor(arr) {
    try {
      let parseColor = function (hexStr) {
        return hexStr.length === 4
          ? hexStr
              .substr(1)
              .split('')
              .map(function (s) {
                return 0x11 * parseInt(s, 16)
              })
          : [hexStr.substr(1, 2), hexStr.substr(3, 2), hexStr.substr(5, 2)].map(function (s) {
              return parseInt(s, 16)
            })
      }

      let pad = function (s) {
        return s.length === 1 ? '0' + s : s
      }

      let gradientColors = function (start, end, steps, gamma) {
        let i
        let j
        let ms
        let me
        let output = []
        let so = []
        gamma = gamma || 1
        let normalize = function (channel) {
          return Math.pow(channel / 255, gamma)
        }
        start = parseColor(start).map(normalize)
        end = parseColor(end).map(normalize)
        for (i = 0; i < steps; i++) {
          ms = i / (steps - 1)
          me = 1 - ms
          for (j = 0; j < 3; j++) {
            so[j] = pad(Math.round(Math.pow(start[j] * me + end[j] * ms, 1 / gamma) * 255).toString(16))
          }
          output.push('#' + so.join(''))
        }
        return output
      }
      return gradientColors(arr[0], arr[1], 3)[1]
    } catch (err) {
      return arr[0]
    }
  }

  .color-select {
    position: relative;
    user-select: none;
    width: 300px;
    background: #fff;
    padding: 10px;
    /*border: 1px solid #ccc;*/
    /*border-radius: 10px;*/
  }

  /* 饱和度和亮度 */
  .saturation-value {
    cursor: pointer;
    width: 100%;
    height: 200px;
    position: relative;
    margin-bottom: 10px;
    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);
  }

  /* 色调 透明度 */
  .color-select-middle {
    width: 100%;
    display: flex;
    margin-bottom: 10px;
  }

  .slider-item + .slider-item {
    margin-top: 6px;
  }

  /* 色调滑块条 */
  .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);
    width: 100%;
  }

  /* 透明度滑块条 */
  .alpha-slider {
    position: relative;
    height: 10px;
    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;
    width: 100%;
  }

  /* 滑块 */
  .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;
  }

  .color-slider {
    flex: auto;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
  }

  /* 颜色方块 */
  .color-diamond {
    position: relative;
    margin-left: 5px;
    width: 26px;
    height: 26px;
    border-radius: 3px;
    overflow: hidden;
    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAWElEQVRIiWM8fubkfwYygKWJOSM5+mCAhRLNoxaPWjxq8ajFoxbTyeL/DAfJ0Xjs3Cl7Siwmu4Yht1aDgZEYx6MWj1o8avGoxaMWD3qLya5X//4nqx6HAQC7RBGFzolqTAAAAABJRU5ErkJggg==');
    background-size: 10px 10px;
  }

  /* 颜色的值 hex rgba */
  .color-value {
    width: 100%;
    display: flex;
    justify-content: space-between;
  }

  .color-value div {
    padding: 0 3px;
    text-align: center;
  }

  .color-value input {
    font-size: 12px;
    box-sizing: border-box;
    width: 34px;
    height: 24px;
    padding: 0;
    margin: 0;
    outline: none;
    text-align: center;
    border-radius: 3px;
    border: 1px solid #ccc;
  }

  .color-value p {
    font-size: 12px;
    margin: 3px 0 0;
  }

  .color-value .rgba-a {
    padding-right: 0;
  }

  .color-value .hex {
    flex: 1;
    padding-left: 0;
  }

  .color-value .hex input {
    width: 100%;
    height: 24px;
  }

  /* 预设颜色  */
  .predefine {
    width: 100%;
    padding: 0;
    margin: 10px 0 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
  }

  .predefine-item {
    width: 20px;
    height: 20px;
    margin-bottom: 6px;
    border: 1px solid #ccc;
    border-radius: 6px;
  }
  .predefine-item + .predefine-item {
    margin-left: 6px;
  }
  .predefine-item:nth-child(12n) {
    margin-left: 0;
  }
  .color-actions {
    font-size: 12px;
    text-align: right;
  }
  .color-actions span {
    padding: 5px 12px;
    line-height: 12px;
    display: inline-block;
    box-sizing: border-box;
    border: 1px solid transparent;
  }
  .color-actions .cancel:hover {
    background-color: #f5f7fa;
  }
  .color-actions .confirm {
    border-color: #dcdfe6;
    border-radius: 4px;
    margin-left: 10px;
  }
  .color-actions .confirm:hover {
    color: #1677ff;
    border-color: #1677ff;
  }

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值