123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <el-popover
- v-model:visible="visible"
- class="inline-block"
- trigger="click"
- :show-arrow="false"
- :hide-after="50"
- placement="bottom-start"
- :width="250"
- popper-class="color-picker-popover"
- >
- <div class="relative">
- <div class="color-box">
- <p>选择颜色</p>
- <ul class="flex flex-wrap p-extra-small color-list">
- <li
- v-for="color in defaultColors"
- :key="color"
- class="color-item"
- :class="{ active: customColor === color }"
- :style="{ '--color': color }"
- @click="checkColor(color)"
- ></li>
- </ul>
- </div>
- <div class="color-box">
- <p>自定义颜色</p>
- <ul class="flex flex-wrap p-extra-small color-list">
- <li
- v-for="color in historyColors"
- :key="color"
- class="color-item"
- :class="{ active: customColor === color }"
- :style="{ '--color': color }"
- @click="checkColor(color)"
- ></li>
- </ul>
- </div>
- <div class="custom-color-button" @click="onCustomPicker">选择自定义颜色</div>
- <div class="flex items-center justify-between m-t-base confirm-buttons">
- <el-button size="small" type="primary" @click="onConfirm">确定</el-button>
- <el-button size="small" type="primary" plain @click="toggleVisible(false)">取消</el-button>
- </div>
- <input ref="colorInput" v-model="customColor" class="color-input" type="color" />
- </div>
- <template #reference><slot></slot></template>
- </el-popover>
- </template>
- <script setup lang="ts" name="ColorPicker">
- import { reactive, ref, watch } from 'vue'
- import { debounce } from 'lodash-es'
- import { ElPopover, ElButton } from 'element-plus'
- import { localStorage } from '@/plugins/storage'
- const props = defineProps<{
- modelValue: string
- }>()
- const emits = defineEmits<{ (e: 'update:modelValue', color: string): void }>()
- const visible = ref<boolean>(false)
- const defaultColors = [
- '#fe7e7d',
- '#feff7e',
- '#81ff81',
- '#01fe7f',
- '#80fffe',
- '#0080ff',
- '#fd7fc3',
- '#ff7ffd',
- '#fe0002',
- '#fffc00',
- '#80fe00',
- '#00ff43',
- '#04fdfd',
- '#007fc1',
- '#7f81b7',
- '#fe02f3',
- '#803f40',
- '#fb823e',
- '#05fc03',
- '#018184',
- '#043e7b',
- '#817eff',
- '#810141',
- '#fb0182',
- ]
- const historyColors = ref<string[]>(localStorage.get('HISTORY_CUSTOM_COLOR') || [])
- const customColor = ref<string>(props.modelValue)
- watch(props, () => {
- customColor.value = props.modelValue
- })
- watch(
- customColor,
- debounce(() => {
- if (customColor.value && !defaultColors.concat(historyColors.value).includes(customColor.value)) {
- if (historyColors.value.length >= 16) {
- historyColors.value = [customColor.value].concat(historyColors.value.slice(0, 15))
- } else {
- historyColors.value.unshift(customColor.value)
- }
- }
- }, 50)
- )
- watch(
- historyColors,
- debounce(() => {
- localStorage.set('HISTORY_CUSTOM_COLOR', [...new Set(historyColors.value.slice(0, 16))])
- }, 50)
- )
- const checkColor = (color: string) => {
- customColor.value = color
- }
- const colorInput = ref<HTMLInputElement>()
- const onCustomPicker = () => {
- colorInput.value?.click()
- }
- const toggleVisible = (v: boolean) => {
- visible.value = v
- }
- const onConfirm = () => {
- toggleVisible(false)
- emits('update:modelValue', customColor.value)
- }
- </script>
- <style scoped lang="scss">
- .color-box {
- color: $NormalColor;
- .color-list {
- margin-left: -6px;
- .color-item {
- width: 20px;
- height: 20px;
- background-color: var(--color);
- margin-left: 6px;
- margin-bottom: 9px;
- transition: scale 0.1s linear;
- &:hover {
- transform: scale(1.15);
- }
- &.active {
- outline: 1px dashed red;
- }
- }
- }
- }
- .custom-color-button {
- color: $NormalColor;
- height: 32px;
- line-height: 32px;
- border-radius: 2px;
- margin: 6px 0;
- background-color: rgba(0, 0, 0, 0.1);
- text-align: center;
- cursor: pointer;
- &:hover {
- background-color: rgba(0, 0, 0, 0.08);
- }
- }
- .confirm-buttons {
- .el-button {
- width: 100px;
- }
- }
- .color-input {
- width: 0;
- height: 0;
- border: none;
- outline: none;
- opacity: 0;
- position: absolute;
- right: -30px;
- top: 0;
- }
- </style>
|