feat: 添加搜索下拉框

This commit is contained in:
zxc 2024-08-25 15:55:53 +08:00
parent ee9ddf4722
commit 3d21bfd5c6
9 changed files with 69 additions and 12 deletions

View File

@ -1,7 +1,7 @@
<template> <template>
<div :class="['divider', type]" <div :class="['divider', type]"
:style="{ :style="{
margin: type === 'horizontal' ? `${margin || 24}px 0` : `0 ${margin || 8}px` margin: type === 'horizontal' ? `${margin >= 0 ? margin : 24}px 0` : `0 ${margin >= 0 ? margin : 8}px`
}" }"
></div> ></div>
</template> </template>
@ -12,7 +12,7 @@ withDefaults(defineProps<{
margin?: number margin?: number
}>(), { }>(), {
type: 'horizontal', type: 'horizontal',
margin: 0, margin: -1,
}) })
</script> </script>

View File

@ -4,6 +4,7 @@
:class="{ :class="{
'disabled': disabled, 'disabled': disabled,
'focused': focused, 'focused': focused,
'simple': simple,
}" }"
> >
<span class="prefix"> <span class="prefix">
@ -34,9 +35,11 @@ withDefaults(defineProps<{
value: string value: string
disabled?: boolean disabled?: boolean
placeholder?: string placeholder?: string
simple?: boolean
}>(), { }>(), {
disabled: false, disabled: false,
placeholder: '', placeholder: '',
simple: false,
}) })
const emit = defineEmits<{ const emit = defineEmits<{
@ -114,6 +117,10 @@ defineExpose({
} }
} }
&.simple {
border: 0;
}
.prefix, .suffix { .prefix, .suffix {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -21,13 +21,17 @@
v-else v-else
> >
<template #content> <template #content>
<template v-if="search">
<Input ref="searchInputRef" simple :placeholder="searchLabel" v-model:value="searchKey" :style="{ width: width + 2 + 'px' }" />
<Divider :margin="0" />
</template>
<div class="options" :style="{ width: width + 2 + 'px' }"> <div class="options" :style="{ width: width + 2 + 'px' }">
<div class="option" <div class="option"
:class="{ :class="{
'disabled': option.disabled, 'disabled': option.disabled,
'selected': option.value === value, 'selected': option.value === value,
}" }"
v-for="option in options" v-for="option in showOptions"
:key="option.value" :key="option.value"
@click="handleSelect(option)" @click="handleSelect(option)"
>{{ option.label }}</div> >{{ option.label }}</div>
@ -47,6 +51,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref } from 'vue' import { computed, onMounted, onUnmounted, ref } from 'vue'
import Popover from './Popover.vue' import Popover from './Popover.vue'
import Input from './Input.vue'
import Divider from './Divider.vue'
import { watch } from 'vue';
import { nextTick } from 'vue';
import { onBeforeUnmount } from 'vue';
interface SelectOption { interface SelectOption {
label: string label: string
@ -58,12 +67,12 @@ const props = withDefaults(defineProps<{
value: string | number value: string | number
options: SelectOption[] options: SelectOption[]
disabled?: boolean disabled?: boolean
search?: boolean
searchLabel?: string
}>(), { }>(), {
disabled: false, disabled: false,
}) search: false,
searchLabel: '搜索',
const showLabel = computed(() => {
return props.options.find(item => item.value === props.value)?.label || props.value
}) })
const emit = defineEmits<{ const emit = defineEmits<{
@ -72,7 +81,34 @@ const emit = defineEmits<{
const popoverVisible = ref(false) const popoverVisible = ref(false)
const selectRef = ref<HTMLElement>() const selectRef = ref<HTMLElement>()
const searchInputRef = ref<InstanceType<typeof Input>>()
const width = ref(0) const width = ref(0)
const searchKey = ref('')
const showLabel = computed(() => {
return props.options.find(item => item.value === props.value)?.label || props.value
})
const showOptions = computed(() => {
if (!props.search) return props.options
if (!searchKey.value.trim()) return props.options
const opts = props.options.filter(item => {
return item.label.toLowerCase().indexOf(searchKey.value.toLowerCase()) !== -1
})
return opts.length ? opts : props.options
})
watch(popoverVisible, () => {
if (popoverVisible.value) {
nextTick(() => {
if (searchInputRef.value) searchInputRef.value.focus()
})
}
else searchKey.value = ''
})
onBeforeUnmount(() => {
searchKey.value = ''
})
const updateWidth = () => { const updateWidth = () => {
if (!selectRef.value) return if (!selectRef.value) return

View File

@ -74,7 +74,7 @@
</div> </div>
<div class="configs" v-if="handleElementAnimation[0]?.elId === element.elId"> <div class="configs" v-if="handleElementAnimation[0]?.elId === element.elId">
<Divider style="margin: 16px 0;" /> <Divider :margin="16" />
<div class="config-item"> <div class="config-item">
<div style="width: 35%;">持续时长</div> <div style="width: 35%;">持续时长</div>

View File

@ -54,6 +54,8 @@
<Select <Select
style="width: 60%;;" style="width: 60%;;"
:value="richTextAttrs.fontname" :value="richTextAttrs.fontname"
search
searchLabel="搜索字体"
@update:value="value => updateFontStyle('fontname', value as string)" @update:value="value => updateFontStyle('fontname', value as string)"
:options="[ :options="[
...availableFonts, ...availableFonts,
@ -67,6 +69,8 @@
<Select <Select
style="width: 40%;" style="width: 40%;"
:value="richTextAttrs.fontsize" :value="richTextAttrs.fontsize"
search
searchLabel="搜索字号"
@update:value="value => updateFontStyle('fontsize', value as string)" @update:value="value => updateFontStyle('fontsize', value as string)"
:options="fontSizeOptions.map(item => ({ :options="fontSizeOptions.map(item => ({
label: item, value: item label: item, value: item

View File

@ -4,6 +4,8 @@
<Select <Select
style="width: 50%;" style="width: 50%;"
:value="textAttrs.fontname" :value="textAttrs.fontname"
search
searchLabel="搜索字体"
@update:value="value => updateTextAttrs({ fontname: value as string })" @update:value="value => updateTextAttrs({ fontname: value as string })"
:options="[ :options="[
...availableFonts, ...availableFonts,
@ -17,6 +19,8 @@
<Select <Select
style="width: 50%;" style="width: 50%;"
:value="textAttrs.fontsize" :value="textAttrs.fontsize"
search
searchLabel="搜索字号"
@update:value="value => updateTextAttrs({ fontsize: value as string })" @update:value="value => updateTextAttrs({ fontsize: value as string })"
:options="fontSizeOptions.map(item => ({ :options="fontSizeOptions.map(item => ({
label: item, value: item label: item, value: item

View File

@ -128,6 +128,8 @@
<Select <Select
style="width: 60%;" style="width: 60%;"
:value="theme.fontName" :value="theme.fontName"
search
searchLabel="搜索字体"
@update:value="value => updateTheme({ fontName: value as string })" @update:value="value => updateTheme({ fontName: value as string })"
:options="[ :options="[
...availableFonts, ...availableFonts,

View File

@ -5,6 +5,8 @@
class="font-select" class="font-select"
style="width: 60%;" style="width: 60%;"
:value="richTextAttrs.fontname" :value="richTextAttrs.fontname"
search
searchLabel="搜索字体"
@update:value="value => emitRichTextCommand('fontname', value as string)" @update:value="value => emitRichTextCommand('fontname', value as string)"
:options="[ :options="[
...availableFonts, ...availableFonts,
@ -18,6 +20,8 @@
<Select <Select
style="width: 40%;" style="width: 40%;"
:value="richTextAttrs.fontsize" :value="richTextAttrs.fontsize"
search
searchLabel="搜索字号"
@update:value="value => emitRichTextCommand('fontsize', value as string)" @update:value="value => emitRichTextCommand('fontsize', value as string)"
:options="fontSizeOptions.map(item => ({ :options="fontSizeOptions.map(item => ({
label: item, value: item label: item, value: item

View File

@ -46,7 +46,7 @@
><IconFontSize />-</Button> ><IconFontSize />-</Button>
</ButtonGroup> </ButtonGroup>
<Divider style="margin: 20px 0;" /> <Divider :margin="20" />
<RadioGroup <RadioGroup
class="row" class="row"
@ -59,7 +59,7 @@
<RadioButton value="right" style="flex: 1;"><IconAlignTextRight /></RadioButton> <RadioButton value="right" style="flex: 1;"><IconAlignTextRight /></RadioButton>
</RadioGroup> </RadioGroup>
<Divider style="margin: 20px 0;" /> <Divider :margin="20" />
<div class="row-block"> <div class="row-block">
<div class="label">文字颜色</div> <div class="label">文字颜色</div>
@ -93,7 +93,7 @@
<Button style="flex: 1;" @click="deleteElement()"><IconDelete class="icon" /> 删除</Button> <Button style="flex: 1;" @click="deleteElement()"><IconDelete class="icon" /> 删除</Button>
</ButtonGroup> </ButtonGroup>
<Divider style="margin: 20px 0;" /> <Divider :margin="20" />
<ButtonGroup class="row"> <ButtonGroup class="row">
<Button style="flex: 1;" @click="orderElement(handleElement!, ElementOrderCommands.TOP)"><IconSendToBack class="icon" /> 置顶</Button> <Button style="flex: 1;" @click="orderElement(handleElement!, ElementOrderCommands.TOP)"><IconSendToBack class="icon" /> 置顶</Button>
@ -102,7 +102,7 @@
<Button style="flex: 1;" @click="orderElement(handleElement!, ElementOrderCommands.DOWN)"><IconSentToBack class="icon" /> 下移</Button> <Button style="flex: 1;" @click="orderElement(handleElement!, ElementOrderCommands.DOWN)"><IconSentToBack class="icon" /> 下移</Button>
</ButtonGroup> </ButtonGroup>
<Divider style="margin: 20px 0;" /> <Divider :margin="20" />
<ButtonGroup class="row"> <ButtonGroup class="row">
<Button style="flex: 1;" @click="alignElementToCanvas(ElementAlignCommands.LEFT)"><IconAlignLeft class="icon" /> 左对齐</Button> <Button style="flex: 1;" @click="alignElementToCanvas(ElementAlignCommands.LEFT)"><IconAlignLeft class="icon" /> 左对齐</Button>