svg 可改颜色,但似乎不支持微信小程序

javascript 复制代码
<!-- components/SvgIcon/SvgIcon.vue -->
<template>
  <view
    class="svg-icon"
    :class="[customClass, { 'svg-icon--clickable': !disabled && !!$attrs.onClick }]"
    :style="computedStyles"
    @click="handleClick"
    @touchstart="handleTouchStart"
    @touchend="handleTouchEnd"
  >
    <!-- 加载状态 -->
    <view v-if="loading" class="svg-icon__loading">
      <text class="loading-text">...</text>
    </view>

    <!-- 错误回退 -->
    <text v-else-if="showFallback" class="svg-icon__fallback">□</text>
  </view>
</template>

<script setup>
import { computed, ref, watch, onMounted } from 'vue'

// 定义 Props
const props = defineProps({
  // 图标名称(对应 static/svg 目录下的文件名)
  name: {
    type: String,
    required: true,
  },
  // 图标大小
  size: {
    type: [Number, String],
    default: 88,
  },
  // 图标颜色
  color: {
    type: String,
    default: 'unset',
  },
  disabledColor: {
    type: String,
    default: '#999999',
  },
  // 自定义类名
  customClass: {
    type: String,
    default: '',
  },
  // 自定义样式
  customStyle: {
    type: Object,
    default: () => ({}),
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
  // 是否显示加载状态
  loading: {
    type: Boolean,
    default: false,
  },
})

// 定义 Emits
const emit = defineEmits(['click', 'error'])

// 响应式数据
const iconLoaded = ref(false)
const showFallback = ref(false)
const isTouching = ref(false)

// 计算属性
const iconPath = computed(() => {
  return `/static/svg/${props.name}.svg`
})

const computedSize = computed(() => {
  if (typeof props.size === 'number') {
    return props.size + 'rpx'
  }
  if (
    props.size.includes('rpx') ||
    props.size.includes('px') ||
    props.size.includes('em') ||
    props.size.includes('%')
  ) {
    return props.size
  }
  return props.size + 'rpx'
})

const computedStyles = computed(() => {
  const baseStyles = {
    width: computedSize.value,
    height: computedSize.value,
    color: props.disabled ? props.disabledColor : props.color,
    'mask-image': `url(${iconPath.value})`,
    '-webkit-mask-image': `url(${iconPath.value})`,
    pointerEvents: props.disabled ? 'none' : 'auto',
  }
  return { ...baseStyles, ...props.customStyle }
})

// 方法
const handleClick = (event) => {
  if (!props.disabled && !props.loading) {
    emit('click', event)
  }
}

const handleTouchStart = () => {
  if (!props.disabled && !props.loading) {
    isTouching.value = true
  }
}

const handleTouchEnd = () => {
  isTouching.value = false
}

// 图标加载处理
const checkIconExists = async () => {
  return new Promise((resolve) => {
    const img = new Image()
    img.onload = () => resolve(true)
    img.onerror = () => resolve(false)
    img.src = iconPath.value
  })
}

const loadIcon = async () => {
  try {
    const exists = await checkIconExists()
    if (exists) {
      iconLoaded.value = true
      showFallback.value = false
    } else {
      iconLoaded.value = false
      showFallback.value = true
      emit('error', new Error(`图标不存在: ${props.name}`))
    }
  } catch (error) {
    iconLoaded.value = false
    showFallback.value = true
    emit('error', error)
  }
}

// 监听图标名称变化
watch(() => props.name, loadIcon, { immediate: true })

// 生命周期
onMounted(() => {
  loadIcon()
})
</script>

<style scoped>
.svg-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-color: currentColor;
  mask-repeat: no-repeat;
  mask-position: center;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
  transition: all 0.3s ease;
  flex-shrink: 0;
  vertical-align: middle;
}

.svg-icon--clickable {
  cursor: pointer;
}

.svg-icon--clickable:active {
  opacity: 0.7;
  transform: scale(0.95);
}

.svg-icon__loading {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.loading-text {
  font-size: 12px;
  color: inherit;
}

.svg-icon__fallback {
  font-size: 24px;
  color: #ccc;
}
</style>
相关推荐
Ai-_Man1 小时前
希望大家能推荐一款软件,可以直接把文心生成的代码变流程图,提高办公效率
人工智能·ai·小程序·流程图
Chengbei116 小时前
DSH渗透测试插件dsh-pentest全新升级!适配DeepSeek Harness,可视化探索链路,一键搭建轻量化AI渗透测试环境。
人工智能·web安全·网络安全·微信·小程序·系统安全·安全架构
2601_949950639 小时前
用练题簿小程序把课件做成可以在线刷题的内容
小程序·练习·小程序推荐
一几文12 小时前
2026年上半年软考高级-系统架构设计师考试真题回顾与解析-综合知识选择题6
小程序·架构·系统架构·软考高级·软考·it证书
zhangminghuan15 小时前
微信小程序开发核心知识点全景解析(前端必备硬核基础)
前端·微信小程序·小程序
游戏开发爱好者816 小时前
开心上架是什么,一站式 Apple 开发者工作台总览
android·小程序·https·uni-app·iphone·webview
sltin18 小时前
需求到落地:我如何在微信小程序里实现证件照换底、隐私打码与水印相机
数码相机·微信小程序·小程序
软件聚导航20 小时前
软件聚导航-前端工程师的“小家庭”,工具与生活并存
人工智能·小程序·学习方法·图片压缩
咸虾米_2 天前
小程序流量主哪种广告最赚钱?各类广告收益与实操建议
微信小程序·小程序·小程序开发·流量主广告
show4332 天前
2026小程序端AI配音技术实现:TTS多音色引擎集成与MP3生成性能优化
人工智能·性能优化·小程序