feat(iconPicker): 缓存工作空间

This commit is contained in:
落小梅
2021-10-21 18:16:42 +08:00
parent 01a479bc9a
commit 2e51cb1fab
6 changed files with 497 additions and 4 deletions

View File

@@ -0,0 +1,120 @@
<script lang="ts">
export default {
name: 'ColorBox',
}
</script>
<script setup lang="ts">
import { Nullable } from '/@src/module/type'
import { computed, onMounted, ref } from "vue";
import { HSBToHEX, RGBSTo, RGBToHSB } from '/@src/module/colorPicker/colorUtil'
import ColorPicker from './ColorPicker.vue'
import { usePosition } from "/@src/use/usePosition";
interface BoxProps {
color?: string
size?: Nullable<string>
alpha?: boolean
format?: 'hex' | 'rgb'
predefine?: boolean
colors?: string[],
}
const colorBoxProps = withDefaults(defineProps<BoxProps>(), {
color: '',
size: () => null,
alpha: false,
format: 'hex',
predefine: false,
colors: () => [
//默认预定义颜色列表
'#009688',
'#5FB878',
'#1E9FFF',
'#FF5722',
'#FFB800',
'#01AAED',
'#999',
'#c00',
'#ff8c00',
'#ffd700',
'#90ee90',
'#00ced1',
'#1e90ff',
'#c71585',
'rgb(0, 186, 189)',
'rgb(255, 120, 0)',
'rgb(250, 212, 0)',
'#393D49',
'rgba(0,0,0,.5)',
'rgba(255, 69, 0, 0.68)',
'rgba(144, 240, 144, 0.5)',
'rgba(31, 147, 255, 0.73)',
],
})
const triggerSpanStyle = computed(() => {
let bgstr = ''
if (colorBoxProps.color) {
bgstr = colorBoxProps.color
if ((colorBoxProps.color.match(/[0-9]{1,3}/g) || []).length > 3) {
//需要优化
if (!(colorBoxProps.alpha && colorBoxProps.format == 'rgb')) {
bgstr = '#' + HSBToHEX(RGBToHSB(RGBSTo(colorBoxProps.color)))
}
}
}
return {
background: bgstr,
}
})
const colorPickerWrapper = computed(() => {
return colorBoxProps.size
? `layui-colorpicker-${colorBoxProps.size}`
: ''
})
const colorBoxRefEl = ref<HTMLElement | null>(null)
const colorPickerRefEl = ref<HTMLElement | null>(null)
onMounted(() => {
console.log('colorPickerRefEl =>>>', colorPickerRefEl.value.teleportRefEl)
usePosition(colorBoxRefEl.value, colorPickerRefEl.value.teleportRefEl)
})
</script>
<template>
<div class="layui-unselect layui-colorpicker" ref="colorBoxRefEl">
<span
:class="[
{
'layui-colorpicker-trigger-bgcolor':
format == 'rgb' && alpha,
},
size ? colorPickerWrapper : ''
]"
>
<span
class="layui-colorpicker-trigger-span"
:style="triggerSpanStyle"
>
<!-- ICON_PICKER_DOWN = 'layui-icon-down', ICON_PICKER_CLOSE = 'layui-icon-close' -->
<i
:class="[
'layui-icon layui-colorpicker-trigger-i',
color ? 'layui-icon-down' : 'layui-icon-close',
]"
></i>
</span>
</span>
<ColorPicker
:visible="true"
:alpha="alpha"
:predefine="predefine"
ref="colorPickerRefEl"
></ColorPicker>
</div>
</template>
<style scoped lang="less"></style>

View File

@@ -0,0 +1,91 @@
<script lang="ts">
export default {
name: 'ColorPicker',
}
</script>
<script setup lang="ts">
import { ref } from "vue";
interface CProps {
visible: boolean
alpha: boolean
predefine: boolean
}
const props = defineProps<CProps>()
const domRefEl = ref<HTMLElement | null>(null)
defineExpose({
teleportRefEl: domRefEl
})
</script>
<template>
<teleport to="body">
<div
v-if="visible"
class="layui-anim layui-anim-downbit layui-colorpicker-main"
ref="domRefEl"
>
<!-- //颜色面板-->
<div class="layui-colorpicker-main-wrapper">
<div class="layui-colorpicker-basis">
<div class="layui-colorpicker-basis-white"></div>
<div class="layui-colorpicker-basis-black"></div>
<div class="layui-colorpicker-basis-cursor"></div>
</div>
<div class="layui-colorpicker-side">
<div class="layui-colorpicker-side-slider"></div>
</div>
</div>
<!-- //透明度条块-->
<div
:class="[
{
'layui-colorpicker-main-alpha': true,
'layui-show': alpha,
},
]"
>
<div class="layui-colorpicker-alpha-bgcolor">
<div class="layui-colorpicker-alpha-slider"></div>
</div>
</div>
<!-- //预设颜色列表-->
<div v-if="predefine" class="layui-colorpicker-main-pre">
<div
v-for="c in colors"
:key="c"
:class="{
'layui-colorpicker-pre': true,
'layui-colorpicker-pre-isalpha':
(c.match(/[0-9]{1,3}/g) || []).length > 3,
}"
>
<div :style="{ background: c }"></div>
</div>
</div>
<!-- //底部表单元素区域-->
<div class="layui-colorpicker-main-input">
<div class="layui-inline">
<input type="text" class="layui-input" />
</div>
<div class="layui-btn-container">
<button
class="layui-btn layui-btn-primary layui-btn-sm"
colorpicker-events="clear"
>
清空
</button>
<button
class="layui-btn layui-btn-sm"
colorpicker-events="confirm"
type="submit"
>
确定
</button>
</div>
</div>
</div>
</teleport>
</template>
<style scoped lang="less"></style>

View File

@@ -0,0 +1,34 @@
export interface ColorPickerProps {
/**
* 默认颜色,不管你是使用 hex、rgb 还是 rgba 的格式输入,最终会以指定的格式显示。
* v-model:color
*/
color: string
/**
* 颜色显示/输入格式,可选值: hex、rgb
* 若在 rgb 格式下开启了透明度,格式会自动变成 rgba。在没有输入颜色的前提下组件会默认为 #000 也就是黑色。
* default: hex即 16 进制色值)
*/
format: 'hex' | 'rgb'
/**
* 是否开启透明度,若不开启,则不会显示透明框。开启了透明度选项时,当你的默认颜色为 hex 或 rgb 格式,
* 组件会默认加上值为 1 的透明度。相同的,当你没有开启透明度,却以 rgba 格式设置默认颜色时,组件会默认没有透明度。
* 注意:该参数必须配合 rgba 颜色值使用
* default: false
*/
alpha: boolean
/**
* 预定义颜色是否开启
* default: false
*/
predefine: boolean
/**
* 预定义颜色,此参数需配合 predefine: true 使用。
* 此处列举一部分:['#ff4500','#1e90ff','rgba(255, 69, 0, 0.68)','rgb(255, 120, 0)']
*/
colors: string[]
/**
* 下拉框大小可以选择lg、sm、xs。
*/
size: 'lg' | 'sm' | 'xs'
}

View File

@@ -0,0 +1,113 @@
export interface RGB {
h: number
s: number
b: number
}
// RGB转HSB
export function RGBToHSB(rgb: any) {
const hsb = { h: 0, s: 0, b: 0 }
const min = Math.min(rgb.r, rgb.g, rgb.b)
const max = Math.max(rgb.r, rgb.g, rgb.b)
const delta = max - min
hsb.b = max
hsb.s = max != 0 ? (255 * delta) / max : 0
if (hsb.s != 0) {
if (rgb.r == max) {
hsb.h = (rgb.g - rgb.b) / delta
} else if (rgb.g == max) {
hsb.h = 2 + (rgb.b - rgb.r) / delta
} else {
hsb.h = 4 + (rgb.r - rgb.g) / delta
}
} else {
hsb.h = -1
}
if (max == min) {
hsb.h = 0
}
hsb.h *= 60
if (hsb.h < 0) {
hsb.h += 360
}
hsb.s *= 100 / 255
hsb.b *= 100 / 255
return hsb
}
// HEX转HSB
export function HEXToHSB(hex: any) {
hex = hex.indexOf('#') > -1 ? hex.substring(1) : hex
if (hex.length == 3) {
const num = hex.split('')
hex = num[0] + num[0] + num[1] + num[1] + num[2] + num[2]
}
hex = parseInt(hex, 16)
const rgb = { r: hex >> 16, g: (hex & 0x00ff00) >> 8, b: hex & 0x0000ff }
return RGBToHSB(rgb)
}
// HSB转RGB
export function HSBToRGB(hsb: any) {
const rgb: any = {}
let h = hsb.h
const s = (hsb.s * 255) / 100
const b = (hsb.b * 255) / 100
if (s == 0) {
rgb.r = rgb.g = rgb.b = b
} else {
const t1 = b
const t2 = ((255 - s) * b) / 255
const t3 = ((t1 - t2) * (h % 60)) / 60
if (h == 360) h = 0
if (h < 60) {
rgb.r = t1
rgb.b = t2
rgb.g = t2 + t3
} else if (h < 120) {
rgb.g = t1
rgb.b = t2
rgb.r = t1 - t3
} else if (h < 180) {
rgb.g = t1
rgb.r = t2
rgb.b = t2 + t3
} else if (h < 240) {
rgb.b = t1
rgb.r = t2
rgb.g = t1 - t3
} else if (h < 300) {
rgb.b = t1
rgb.g = t2
rgb.r = t2 + t3
} else if (h < 360) {
rgb.r = t1
rgb.g = t2
rgb.b = t1 - t3
} else {
rgb.r = 0
rgb.g = 0
rgb.b = 0
}
}
return { r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b) }
}
// HSB转HEX
export function HSBToHEX(hsb: any) {
const rgb = HSBToRGB(hsb)
const hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)]
hex.forEach((val, nr) => {
if (val.length == 1) {
hex[nr] = '0' + val
}
})
return hex.join('')
}
//转化成所需rgb格式
export function RGBSTo(rgbs: any) {
const regexp = /[0-9]{1,3}/g
const re = rgbs.match(regexp) || []
return { r: re[0], g: re[1], b: re[2] }
}

View File

@@ -4,10 +4,55 @@ export default {
}
</script>
<script lang="ts" setup></script>
<script lang="ts" setup>
import { Nullable } from '/@src/module/type'
import ColorBox from './ColorBox.vue'
interface ColorPickerProps {
color?: string
size?: Nullable<string>
alpha?: boolean
format?: 'hex' | 'rgb'
predefine?: boolean
colors?: string[]
}
const colorPickerProps = withDefaults(defineProps<ColorPickerProps>(), {
color: '',
size: () => null,
alpha: false,
format: 'hex',
predefine: false,
colors: () => [
//默认预定义颜色列表
'#009688',
'#5FB878',
'#1E9FFF',
'#FF5722',
'#FFB800',
'#01AAED',
'#999',
'#c00',
'#ff8c00',
'#ffd700',
'#90ee90',
'#00ced1',
'#1e90ff',
'#c71585',
'rgb(0, 186, 189)',
'rgb(255, 120, 0)',
'rgb(250, 212, 0)',
'#393D49',
'rgba(0,0,0,.5)',
'rgba(255, 69, 0, 0.68)',
'rgba(144, 240, 144, 0.5)',
'rgba(31, 147, 255, 0.73)',
],
})
</script>
<template>
<pre>
// todo =_=
</pre>
<div class="layui-inline'">
<ColorBox></ColorBox>
</div>
</template>