2021-01-21 23:17:45 +08:00

133 lines
3.1 KiB
Vue

<template>
<div class="hue">
<div
class="hue-container"
ref="hueRef"
@mousedown="$event => handleMouseDown($event)"
>
<div
class="hue-pointer"
:style="{ left: pointerLeft }"
>
<div class="hue-picker"></div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onUnmounted, PropType, ref, watch } from 'vue'
import tinycolor, { ColorFormats } from 'tinycolor2'
export default defineComponent({
name: 'hue',
props: {
value: {
type: Object as PropType<ColorFormats.RGBA>,
required: true,
},
hue: {
type: Number,
required: true,
},
},
setup(props, { emit }) {
const oldHue = ref(0)
const pullDirection = ref('')
const color = computed(() => {
const hsla = tinycolor(props.value).toHsl()
if(hsla.s === 0) hsla.h = props.hue
return hsla
})
const pointerLeft = computed(() => {
if(color.value.h === 0 && pullDirection.value === 'right') return '100%'
return color.value.h * 100 / 360 + '%'
})
watch(() => props.value, () => {
const hsla = tinycolor(props.value).toHsl()
const h = hsla.s === 0 ? props.hue : hsla.h
if(h !== 0 && h - oldHue.value > 0) pullDirection.value = 'right'
if(h !== 0 && h - oldHue.value < 0) pullDirection.value = 'left'
oldHue.value = h
})
const hueRef = ref<HTMLElement>()
const handleChange = (e: MouseEvent) => {
e.preventDefault()
if(!hueRef.value) return
const containerWidth = hueRef.value.clientWidth
const xOffset = hueRef.value.getBoundingClientRect().left + window.pageXOffset
const left = e.pageX - xOffset
let h, percent
if(left < 0) h = 0
else if(left > containerWidth) h = 360
else {
percent = left * 100 / containerWidth
h = (360 * percent / 100)
}
if(color.value.h !== h) {
emit('change', {
h,
l: color.value.l,
s: color.value.s,
a: color.value.a,
})
}
}
const unbindEventListeners = () => {
window.removeEventListener('mousemove', handleChange)
window.removeEventListener('mouseup', unbindEventListeners)
}
const handleMouseDown = (e: MouseEvent) => {
handleChange(e)
window.addEventListener('mousemove', handleChange)
window.addEventListener('mouseup', unbindEventListeners)
}
onUnmounted(unbindEventListeners)
return {
hueRef,
handleMouseDown,
pointerLeft,
}
},
})
</script>
<style lang="scss" scoped>
.hue {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
.hue-container {
cursor: pointer;
margin: 0 2px;
position: relative;
height: 100%;
}
.hue-pointer {
z-index: 2;
position: absolute;
top: 0;
}
.hue-picker {
cursor: pointer;
margin-top: 1px;
width: 4px;
height: 8px;
box-shadow: 0 0 2px rgba(0, 0, 0, .6);
background: #fff;
transform: translateX(-2px);
}
</style>