I studied vuE3 a few months ago when I was first introduced to it and kept forgetting to share it.
The cause of
My vUE projects generally use dynamically imported SVG-Sprite, which means either a Sprite image, reused with the
Train of thought
- Let’s do one firstvite plugin, as a loader
.svg
File to read the contents of an SVG file, similarraw-loader
. - Then you need a component that dynamically loads the SVG file and splices the content of the SVG file into a Sprite image.
code
Vite. Config. ts:
import {defineConfig, Plugin} from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from "fs";
import {dataToEsm} from "rollup-pluginutils";
const rawSvgPlugin:Plugin = {
name: 'raw-svg-file-loader'.transform(svg: string, filepath: string) {
// Determine whether the suffix is SVG
if (filepath.slice(-4)! = ='.svg') return null;
const content = fs.readFileSync(filepath).toString()
return {
// Returns the original content of the SVG file directly
code: dataToEsm(content)
}
},
}
export default defineConfig({
plugins: [vue(), rawSvgPlugin],
})
Copy the code
IconSvg. Vue file:
<template>
<svg aria-hidden="true">
<use :href="getName"></use>
</svg>
</template>
<script lang="ts">
import {defineComponent} from "vue";
const svgParser = new DOMParser();
export default defineComponent({
name: "IconSvg".props: {
name: {
type: String.default: ' '
}
},
data (){
return {
getName: ' '}},watch: {
// Listen for name changes
'$props.name': {
// First execution
immediate: true.async handler (){
// Concatenate SVG file names
const getId = `icon-The ${this.name}`
const name = ` #${getId}`
// Dynamic loading
const res = await import(`.. /svg/The ${this.name}.svg`);
// Sprite map DOM container
let container = document.querySelector('#_SVG_SPRITE_CONTAINER_');
if(! container || ! container.querySelector(name)) {if(! container) {// Create a container if you haven't already. (You can also write it directly in index.html)
container = document.createElement('div');
container.id = '_SVG_SPRITE_CONTAINER_'
container.setAttribute('xmlns'.'http://www.w3.org/2000/svg')
container.setAttribute('style'.'position: absolute; width: 0; height: 0; overflow: hidden')
document.body.insertBefore(container, document.body.children[0]);
}
if(! container.querySelector(name)) {// If the SVG does not exist in the container, parse and make a Sprite diagram of the SVG
const svgElement = svgParser.parseFromString(res.default, "image/svg+xml").querySelector('svg');
if (svgElement) {
// Remove attributes that affect styles
for (const key of ['width'.'height'.'x'.'y']) {
svgElement.removeAttribute(key)
}
svgElement.id = getId
// Insert into the container
container.appendChild(svgElement as SVGSVGElement)
}
}
}
this.getName = name; }}}})</script>
Copy the code
In main.ts you only need to register the IconSvg component globally:
import { createApp } from 'vue'
import App from './App.vue'
import IconSvg from "./assets/svg/IconSvg.vue";
createApp(App).component('svg-icon', IconSvg).mount('#app')
Copy the code
Use it like this:
<! -- home.svg -->
<svg-icon name="home"/>
Copy the code
summary
This solves the problem, you can dynamically import SVG and generate Sprite images, but it’s a bit unelegant and a bit opportunistic
This article reprints my personal blog: how to use dynamic imported SVG-sprite-cloud with original blog (halberd.cn) under vite+vue3.