重构IconPicker组件
This commit is contained in:
parent
d7be207545
commit
5217ca41d2
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user