feat: 修复菜单图标bug

This commit is contained in:
2026-10-08 20:06:43 +08:00
parent 1650383670
commit 123a73e5ca
@@ -1,5 +1,10 @@
<template> <template>
<div ref="svgContainer" class="svg-icon" :style="{ 'font-size': size + 'px' }"></div> <span class="svg-icon" :style="{ fontSize: size + 'px', width: size + 'px', height: size + 'px' }">
<i v-if="failed" class="el-icon-picture-outline" aria-hidden="true"></i>
<i v-else-if="isFontIcon" :class="fontIconClass" aria-hidden="true"></i>
<img v-else-if="isImageUrl" :src="iconName" alt="" style="width: 100%; height: 100%; object-fit: contain" @error="failed = true" />
<span v-else ref="svgContainer" style="display: inline-flex; width: 100%; height: 100%; overflow: hidden"></span>
</span>
</template> </template>
<script> <script>
@@ -16,21 +21,66 @@ module.exports = {
}, },
data() { data() {
return {} return { failed: false, requestId: 0 }
}, },
methods: {}, computed: {
created() { iconName() {
if (this.name) { return (this.name || "").trim()
fetch("/assets/platform/img/svg/" + this.name + ".svg") },
.then(async (res) => { isFontIcon() {
const svg = await res.text() return /^(?:fa(?:s|r|b|l|d)?(?:\s|$)|fa-|el-icon-|ti-)/.test(this.iconName)
if (this.$refs.svgContainer) { },
this.$refs.svgContainer.innerHTML = "" fontIconClass() {
this.$refs.svgContainer.innerHTML = svg return this.iconName.startsWith("fa-") ? "fa " + this.iconName : this.iconName
},
isImageUrl() {
return /^(?:https?:\/\/|\/|\.\.?\/|data:image\/)/i.test(this.iconName)
} }
}) },
.catch(() => {}) watch: {
name() {
this.loadIcon()
} }
},
methods: {
async loadIcon() {
const requestId = ++this.requestId
this.failed = false
await this.$nextTick()
if (requestId !== this.requestId) return
const container = this.$refs.svgContainer
if (container) container.textContent = ""
if (!this.iconName || this.isFontIcon || this.isImageUrl) return
const fileName = this.iconName.replace(/\.svg$/i, "")
if (!/^[\w-]+$/.test(fileName)) {
this.failed = true
return
}
try {
const response = await fetch("/assets/platform/img/svg/" + encodeURIComponent(fileName) + ".svg")
if (!response.ok) throw new Error("图标请求失败")
const document = new DOMParser().parseFromString(await response.text(), "image/svg+xml")
const svg = document.documentElement
if (document.querySelector("parsererror") || svg.localName !== "svg" || svg.namespaceURI !== "http://www.w3.org/2000/svg") {
throw new Error("图标响应不是有效SVG")
}
if (requestId !== this.requestId || !this.$refs.svgContainer) return
svg.style.setProperty("width", "100%", "important")
svg.style.setProperty("height", "100%", "important")
svg.style.setProperty("max-width", "100%", "important")
svg.style.setProperty("max-height", "100%", "important")
svg.style.setProperty("fill", "currentColor")
this.$refs.svgContainer.appendChild(svg)
} catch (error) {
if (requestId === this.requestId) this.failed = true
}
}
},
mounted() {
this.loadIcon()
},
beforeDestroy() {
this.requestId++
} }
} }
</script> </script>
@@ -38,8 +88,19 @@ module.exports = {
<style scoped> <style scoped>
.svg-icon { .svg-icon {
display: inline-flex; display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
overflow: hidden;
vertical-align: middle;
line-height: 1;
font-size: 20px; font-size: 20px;
} }
.svg-icon > i {
font-size: inherit;
line-height: 1;
margin: 0;
}
.svg-icon svg { .svg-icon svg {
width: 1em; width: 1em;
height: 1em; height: 1em;