This is about a Vue 3 app with Vite, not webpack.
For now, as you can see from this issue on vite's issue page, vite doesn't have a convenient way of inlining SVGs without using external plugins. Vite does however, support importing files as raw text strings. As such, I had an idea to use this feature and to inline SVG's by passing the raw SVG strings into an element's v-html
.
It actually works great, the SVG shows up on the page as expected and I can do the usual CSS transforms (the whole purpose of inlining them like this), but it's not perfect. As it currently stands, the element that receives the v-html
directive simply places the provided HTML nested as a child. For example, if I do <span v-html="svgRaw" />
, the final HTML comes out something like this
<span>
<svg>
<!-- SVG attributes go here -->
</svg>
</span>
Is there any way for me to essentially replace the parent element on which v-html
is declared with the top-level element being passed to it? In the above example, it would mean the <span>
just becomes an <svg>
CodePudding user response:
You could create a custom directive that hoists the wrapper element's contents to the parent node:
Use
app.directive()
to create a global directive, namedv-hoist
:// main.js import { createApp } from 'vue' import App from './App.vue' createApp(App) .directive('hoist', el => { // move child to parent if (el.tagName === 'TEMPLATE') { el.parentNode?.appendChild(el.content) } else { ;[...el.children].forEach((child) => el.parentNode?.appendChild(child)) } // remove wrapper el.remove() }) .mount('#app')
In your component, include
v-hoist
on thev-html
wrapper element (also works on<template>
in Vue 3):<span v-html="svgRaw" v-hoist /> <!-- OR --> <template v-html="svgRaw" v-hoist />
CodePudding user response:
Coming from Vue2. I think this still works:
Instead of span
you can use the special Vue tag template
:
<template v-html="svgRaw" />
This will not render <template />
as a tag itself, but render the elements given in v-html
without a parent element.