重构IconPicker组件

This commit is contained in:
jingrow 2025-11-01 20:54:32 +08:00
parent d7be207545
commit 5217ca41d2
2 changed files with 132 additions and 103 deletions

View File

@ -17,19 +17,16 @@
</template> </template>
</n-button> </n-button>
<!-- 图标选择弹窗 --> <!-- 图标选择抽屉 -->
<n-modal <n-drawer
v-model:show="showPicker" v-model:show="showPicker"
preset="dialog" :width="900"
:title="t('Select Icon')" :placement="'right'"
:positive-text="t('Confirm')" :trap-focus="false"
:negative-text="t('Cancel')" :close-on-esc="true"
@positive-click="confirmSelection"
@negative-click="cancelSelection"
size="huge"
:bordered="false"
style="width: 90vw; max-width: 1200px;"
> >
<n-drawer-content :title="t('Select Icon')" :closable="true">
<template #default>
<div class="icon-picker-content"> <div class="icon-picker-content">
<!-- 搜索栏和图标库选择 --> <!-- 搜索栏和图标库选择 -->
<div class="search-section"> <div class="search-section">
@ -104,13 +101,25 @@
</div> </div>
</div> </div>
</div> </div>
</n-modal> </template>
<!-- 底部操作按钮 -->
<template #footer>
<div class="drawer-footer">
<n-button @click="cancelSelection">{{ t('Cancel') }}</n-button>
<n-button type="primary" @click="confirmSelection" :disabled="!tempSelectedIcon">
{{ t('Confirm') }}
</n-button>
</div>
</template>
</n-drawer-content>
</n-drawer>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted, watch } from 'vue'
import { NButton, NModal, NInput, NSelect, useMessage } from 'naive-ui' import { NButton, NDrawer, NDrawerContent, NInput, NSelect, useMessage } from 'naive-ui'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { getIconLibraryConfig, getAvailableIconLibraries, DEFAULT_ICON_LIBRARY } from '@/shared/utils/icon-libraries' import { getIconLibraryConfig, getAvailableIconLibraries, DEFAULT_ICON_LIBRARY } from '@/shared/utils/icon-libraries'
import { t } from '@/shared/i18n' import { t } from '@/shared/i18n'
@ -414,10 +423,27 @@ async function copyIconName(iconName: string) {
message.success(`${t('Icon name copied to clipboard')}: ${fullIconName}`) message.success(`${t('Icon name copied to clipboard')}: ${fullIconName}`)
} }
// modelValue
watch(() => props.modelValue, (newValue) => {
if (newValue !== selectedIcon.value) {
selectedIcon.value = newValue || ''
}
}, { immediate: true })
// //
onMounted(() => { onMounted(() => {
loadAllIcons() loadAllIcons()
}) })
//
function open() {
openPicker()
}
// 使 defineExpose
defineExpose({
open
})
</script> </script>
<style scoped> <style scoped>
@ -433,11 +459,18 @@ onMounted(() => {
} }
.icon-picker-content { .icon-picker-content {
height: 70vh; height: calc(100vh - 120px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.drawer-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
padding-top: 16px;
}
.search-section { .search-section {
margin-bottom: 20px; margin-bottom: 20px;
display: flex; display: flex;
@ -521,6 +554,7 @@ onMounted(() => {
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, nextTick } from 'vue' import { computed, ref } from 'vue'
import { NInput } from 'naive-ui' import { NInput } from 'naive-ui'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import IconPicker from '@/core/components/IconPicker.vue' import IconPicker from '@/core/components/IconPicker.vue'
@ -17,17 +17,12 @@ const iconValue = computed({
} }
}) })
// IconPicker // IconPicker
const iconPickerRef = ref<InstanceType<typeof IconPicker> | null>(null) const iconPickerRef = ref<InstanceType<typeof IconPicker> | null>(null)
// //
async function openIconPicker() { function openIconPicker() {
await nextTick() iconPickerRef.value?.open()
// IconPicker
const triggerButton = iconPickerRef.value?.$el?.querySelector('.icon-trigger') as HTMLElement
if (triggerButton) {
triggerButton.click()
}
} }
</script> </script>
@ -83,15 +78,15 @@ async function openIconPicker() {
</div> </div>
</div> </div>
<!-- 图标选择器隐藏触发按钮通过自定义按钮触发--> <!-- 图标选择器不渲染触发按钮仅用于弹窗-->
<div v-if="canEdit" style="position: absolute; left: -9999px; opacity: 0; pointer-events: none;">
<IconPicker <IconPicker
v-if="canEdit"
ref="iconPickerRef" ref="iconPickerRef"
:model-value="iconValue" :model-value="iconValue"
@update:model-value="iconValue = $event" @update:model-value="iconValue = $event"
style="display: none;"
/> />
</div> </div>
</div>
</template> </template>
<style scoped> <style scoped>