У меня есть проект Vue3 с настройкой Vite, Typescript и сценария для моих компонентов.
Моя цель — получить изображение svg из ведра S3 (то есть внешний URL-адрес) и использовать его как встроенный svg в моем компоненте. Мне нужно иметь возможность устанавливать реквизиты, такие как viewBox, и заполнять сам svg. Я нашел пример того, что я хочу использовать svg внутри проекта (поэтому не с внешним URL-адресом) через эту тему переполнения стека.
В настоящее время я использую fetch, чтобы получить svg, а затем преобразовать его в элемент svg с помощью DomParser. После этого я хочу передать его <component>, но застреваю.
Это мой код:
<template>
<div
class = "svg-box"
:style = "{ height: props.height + 'px', width: props.width + 'px' }">
<component
:is = "dynamicSvg"
v-if = "dynamicSvg"
ref = "icon"
:fill = "props.fill"
:viewBox = "viewBox"
:class = "name" />
</div>
</template>
<script setup lang = "ts">
import {
ref,
onBeforeMount,
} from 'vue'
import type { Ref } from 'vue'
interface dynamicSvgProps {
name?: string
fill?: string
width?: number
height?: number
}
const props = withDefaults(defineProps<dynamicSvgProps>(), {
name: 'placeholder',
})
const dynamicSvg: Ref<string | undefined | null> = ref(null)
const icon: Ref<SVGSVGElement | null> = ref(null)
const svgBox: Ref<SVGSVGElement | null> = ref(null)
const viewBox = '0 0 24 24' // 👈 hardcoded for this example
const fetchSvg = async (svgName: string) => {
let url = `https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/${svgName}.svg`
fetch(url)
.then((response) => response.text())
.then((svgText) => {
const parser = new DOMParser()
const svgElement = parser
.parseFromString(svgText, 'image/svg+xml')
.querySelector('svg')
// svgBox.value.append(svgElement) 👈 if I use this, the svg is appended but not editable with props
// 👇 here I am trying to transform the svg element to a component so I can pass it to <component>, but this doesn't work
const svgComponent = defineComponent(() => {
return { render: () => h('svg', svgElement ) }
})
return svgComponent
})
}
onBeforeMount(async () => {
dynamicSvg.value = await fetchSvg('check') // 👈 for this example I don't use props for the name
})
// 👇 if I would use an internal svg file, the following code would work in stead of using fetchSvg
const importSvg = async (svgName: string): Promise<string | undefined> => {
if (svgName) return await import(`../../assets/icons/${svgName}.svg`)
}
</script>
Есть ли у кого-нибудь опыт использования внешних SVG? Или может помочь указать мне в правильном направлении? Кроме того, является ли использование парсера DOM хорошей идеей или есть лучшее решение?





Хм, превращение его в настоящий компонент означает, что вам нужно превратить строку svg в шаблон, добавив к нему операторы привязки, а затем запустить компилятор шаблона (который вам специально нужно добавить в вашу сборку). Много работы для умеренного результата...
Я думаю, что более простой способ сделать это — удалить тег <svg> и извлечь из него атрибуты и содержимое. Затем вы можете поместить их в свой собственный тег svg, для которого вы установите содержимое с помощью v-html и привяжете и, возможно, замените старые атрибуты:
<svg
v-bind = "attributes"
v-html = "content"
:fill = "fill"
/>
Вы можете извлечь содержимое и атрибуты из документа SVG:
const parseSvg = (svgString) => {
const svgDom = new DOMParser()
.parseFromString(svgText, 'image/svg+xml')
.querySelector('svg')
const attributeEntries = [...svgDom.attributes].map(a => [a.name, a.value])
return {
content: svgDom.innerHTML,
attributes: Object.fromEntries(attributeEntries)
}
}
Вот пример детской площадки