48 lines
1.2 KiB
Vue
48 lines
1.2 KiB
Vue
<script setup lang="ts">
|
||
import { computed, h } from 'vue'
|
||
import * as LucideIcons from 'lucide-vue-next'
|
||
import type { LucideProps } 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('')
|
||
}
|
||
|
||
// 确保 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
|
||
})
|
||
|
||
const iconComponent = computed(() => {
|
||
const iconName = toPascalCase(props.name) as keyof typeof LucideIcons
|
||
const Icon = LucideIcons[iconName] || LucideIcons.AlertCircle
|
||
return () => h(Icon as any, {
|
||
class: props.className,
|
||
style: props.style,
|
||
size: iconSize.value
|
||
} as LucideProps)
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<component :is="iconComponent" />
|
||
</template> |