47 lines
1.0 KiB
Vue
47 lines
1.0 KiB
Vue
<template>
|
||
<component
|
||
:is="iconComponent"
|
||
:class="className"
|
||
:style="style"
|
||
:size="iconSize"
|
||
/>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed } from 'vue'
|
||
import * as LucideIcons from 'lucide-vue-next'
|
||
|
||
interface Props {
|
||
name: string
|
||
className?: string
|
||
style?: Record<string, any>
|
||
size?: number | string
|
||
}
|
||
|
||
const props = withDefaults(defineProps<Props>(), {
|
||
className: '',
|
||
style: () => ({}),
|
||
size: 24
|
||
})
|
||
|
||
// 将kebab-case转换为PascalCase,例如 arrow-left -> ArrowLeft
|
||
const toPascalCase = (str: string) => {
|
||
return str.split('-').map(word =>
|
||
word.charAt(0).toUpperCase() + word.slice(1)
|
||
).join('')
|
||
}
|
||
|
||
const iconComponent = computed(() => {
|
||
const iconName = toPascalCase(props.name) as keyof typeof LucideIcons
|
||
return LucideIcons[iconName] || LucideIcons.AlertCircle
|
||
})
|
||
|
||
// 确保 size 是 number 类型
|
||
const iconSize = computed(() => {
|
||
if (typeof props.size === 'string') {
|
||
const parsed = parseInt(props.size, 10)
|
||
return isNaN(parsed) ? 24 : parsed
|
||
}
|
||
return props.size ?? 24
|
||
})
|
||
</script> |