vue-优雅的使用svg
vue-优雅的使用svg
背景
日前,需要开发一个配置数据表单类的框架,需要考虑框架的扩展性,以及使用的便捷性,其中图标类的引入也在考虑之中。
期望实现的效果是在新增一个svg时,仅将svg文件存放到某一个文件夹下,之后使用时通过类似于<mis-icon icon="name">
这种方式即可使用。
思路
- 全局注册组件
- 使用js读取文件夹下的所有svg导入至项目中
最终使用效果
<template>
<div>
<!-- icon的值为svg文件名 -->
<mis-icon icon="test" className="test-icon"></mis-icon>
</div>
</template>
<script>
export default {
name: 'SvgTest'
}
</script>
<style scoped>
.test-icon{
color: blue;
width: 200px;
height: 200px;
}
.test-icon:hover{
color: lightblue;
}
</style>
以下提供 vue3+vite+js 以及 vue2+webpack5+js 的实现方式
实现 - vue3+vite+js
全局注册组件
在src/compoments
下创建MisIcon.vue
<template>
<svg :class="svgClass" aria-hidden="true" @click="emits('click')">
<use :xlink:href="iconName" />
</svg>
</template>
<script setup>
import { computed } from "@vue/runtime-core";
const props = defineProps({
icon: {
type: String,
required: true,
},
className: {
type: String,
default: "",
},
});
const iconName = computed(() => `#icon-${props.icon}`);
const svgClass = computed(() => {
if (props.className) {
return "svg-icon " + props.className;
} else {
return "svg-icon";
}
});
const emits = defineEmits(["click"]);
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
集中存放svg文件
在src/assets/svg
文件夹下存放所有svg文件
注意:如果需要修改svg的颜色,svg文件中的填充色 fill
必须删除
全局注册组件&全局导入svg
由于Vue3以应用实例方式运行,组件注册需要在main.js
中的app挂钩
注:很多东西都需要与main.js中的app挂钩,我以另外的方式重写了,在这里以官方方式进行代码编写
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import MisIcon from "./compoments/MisIcon.vue";
// 配置全局svg导入用的
import 'virtual:svg-icons-register';
const app = createApp(App);
app.component('MisIcon', MisIcon);
app.mount("#app");
全局导入svg
使用 vite-plugin-svg-icons
插件
npm install vite-plugin-svg-icons -S
根目录下的ve.config.js
文件中
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
function resolve(dir) {
return path.join(__dirname, "./", dir);
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [resolve("src/assets/svg")],
// 指定symbolId格式
symbolId: "icon-[name]",
}),
]
});
src目录下的main.js
中
// main.js
// 配置全局svg导入用的插件
import 'virtual:svg-icons-register';
实现 - vue2+webpack+js
全局注册组件
在src/compoments
下创建MisIcon.vue
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName"/>
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
icon: {
type: String,
required: true,
},
className: {
type: String,
default: '',
},
},
computed: {
iconName () {
return `#icon-${this.icon}`
},
svgClass () {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
},
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
集中存放svg文件
-
在
src/assets/svg
文件夹下存放所有svg文件注意:如果需要修改svg的颜色,svg文件中的填充色
fill
必须删除 -
在
src/assets
下创建svg.js
文件// 读取所有svg文件 const requireAll = requireContext => requireContext.keys().map(requireContext) const req = require.context('/src/assets/svg', false, /\.svg$/) requireAll(req)
全局注册组件并导入svg
// main.js
import '@/assets/svg.js'
import MisIcon from '@/components/MisIcon/icon.vue' // svg组件
// 注册全局插件
Vue.component('mis-icon', MisIcon)
重要的一步 - 配置loader
根目录下的vue.config.js
文件中
const path = require('path')
function resolve(dir) {
return path.join(__dirname, './', dir)
}
module.exports = {
chainWebpack: config => {
config.module
.rule('svg')
.exclude.add(resolve('src/plugins/icon/svg'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/plugins/icon/svg'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
}
ฅ平平庸庸的普通人ฅ