如何实现支持任意Props的Vue图标组件(含TS类型及简化调用)
实现支持直接传入图标名作为属性的Vue组件
核心思路
要实现<Icon navigate_next />这种调用方式,本质是让组件识别值为true的属性键作为图标名称,同时通过TypeScript类型定义实现图标名的自动提示。
方案1:单文件组件(SFC)实现
<template> <!-- 用$attrs绑定额外属性,支持自定义class、style等 --> <span class="material-symbols-outlined" v-bind="$attrs"> {{ iconName }} </span> </template> <script setup lang="ts"> import { computed } from 'vue' // 自定义Material图标名类型(可根据实际使用的图标集扩展) type MaterialIconName = 'navigate_next' | 'home' | 'menu' | 'search' | 'settings'; // 定义Props:允许所有图标名作为可选布尔属性,同时兼容其他任意属性 type IconProps = { [K in MaterialIconName]?: boolean } & Record<string, unknown> & { // 兼容原有name传参方式(可选) name?: string } const props = defineProps<IconProps>() // 计算图标名称:优先取值为true的图标属性,其次兼容name传参 const iconName = computed(() => { // 找到值为true的图标属性键 const matchedIcon = Object.keys(props).find(key => props[key] === true && (key satisfies MaterialIconName) ) as MaterialIconName | undefined return matchedIcon || props.name || '' }) </script>
方案2:TSX组件实现(非SFC)
import { defineComponent, computed } from 'vue' type MaterialIconName = 'navigate_next' | 'home' | 'menu' | 'search' | 'settings'; type IconProps = { [K in MaterialIconName]?: boolean } & Record<string, unknown> & { name?: string } export default defineComponent({ setup(props: IconProps) { const iconName = computed(() => { const matchedIcon = Object.keys(props).find(key => props[key] === true && (key as MaterialIconName) ) as MaterialIconName | undefined return matchedIcon || props.name || '' }) return () => ( <span class="material-symbols-outlined" {...props}> {iconName.value} </span> ) } })
使用示例
<!-- 目标调用方式 --> <Icon navigate_next /> <!-- 同时传递额外属性 --> <Icon home class="text-green-500" style="font-size: 24px" /> <!-- 兼容原有name传参方式 --> <Icon name="search" />
类型优化(可选)
如果使用完整的Material Icons图标集,可安装官方类型包来自动提示所有图标名:
npm install @types/material-icons --save-dev
然后替换自定义的MaterialIconName为:
import type { MaterialIconName } from '@types/material-icons'
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

