版本
vue-cli 5.x
"svg-sprite-loader": "^6.0.11"
定义组件
<template> <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" :class="className" /> <svg v-else class="svg-icon" :class="className" aria-hidden="true"> <use :xlink:href="iconName" /> </svg> </template> <script setup> import { computed, defineProps } from 'vue' import { isExternam as external } from '@/utils/validate' const props = defineProps({ // 显示的svg icon: { type: String, required: true }, // 图标名称 className: { type: String, default: '' } }) // 判断是否为外部图标 const isExternal = computed(() => external(props.icon)) /** * 外部图标样式 */ const styleExternalIcon = computed(() => ({ mask: `url(${props.icon}) no-repeat 50% 50%`, '-webkit-mask': `url(${props.icon}) no-repeat 50% 50%` })) /** * 项目内图标 */ const iconName = computed(() => `#icon-${props.icon}`) </script> <style scoped> .svg-icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } .svg-external-icon { background-color: currentColor; mask-size: cover !important; display: inline-block; } </style>
/** * 判断是否为外部资源 * @param {*} path * @returns */ export const isExternam = (path) => { return /^(https?:|mailto:|tel:)/.test(path) }
加载所以的svg图片
const svgRequire = require.context('./svg', false, /\.svg$/) console.log(svgRequire.keys()) svgRequire.keys().forEach((svgIcon) => svgRequire(svgIcon))
自动注册组件
export default { install: function (app) { const comps = require.context('./', true, /index\.vue$/) comps.keys().forEach((key) => { const compName = 'm-' + key.replace('./', '').split('/')[0] app.component(compName, comps(key).default) }) } }
最后引入
import mLibs from './libs/index'
const app = createApp(App)
app.use(mLibs)
vue.config.js
const { defineConfig } = require('@vue/cli-service') const path = require('path') function resolve(dir) { return path.join(__dirname, dir) } module.exports = defineConfig({ transpileDependencies: true, devServer: { port: 6060 }, chainWebpack(config) { // 设置 svg-sprite-loader // config 为 webpack 配置对象 // config.module 表示创建一个具名规则,以后用来修改规则 config.module // 规则 .rule('svg') // 忽略 .exclude.add(resolve('src/assets/icons')) // 结束 .end() // config.module 表示创建一个具名规则,以后用来修改规则 config.module // 规则 .rule('icons') // 正则,解析 .svg 格式文件 .test(/\.svg$/) // 解析的文件 .include.add(resolve('src/assets/icons')) // 结束 .end() // 新增了一个解析的loader .use('svg-sprite-loader') // 具体的loader .loader('svg-sprite-loader') // loader 的配置 .options({ symbolId: 'icon-[name]' }) // 结束 .end() } })
测试
<template> <span class="svg-container"> <m-svg-icon icon="https://xiaodun-img.oss-cn-guangzhou.aliyuncs.com/images/user.svg" ></m-svg-icon> </span> <m-svg-icon icon="hot1"></m-svg-icon> </template> <script setup></script> <style lang="scss" scoped> .svg-container { padding: 6px 5px 6px 15px; color: #889aa4; vertical-align: middle; display: inline-block; } </style>
vite 的处理方式,这个是tailwind写法,如果没有,同上
定义组件
<template> <svg aria-hidden="true"> <use :xlink:href="symbolId" :class="fillClass" :fill="color" /> </svg> </template> <script setup> import { computed } from 'vue' const props = defineProps({ // 显示的svg name: { type: String, required: true }, // svg 图标颜色 color: { type: String }, // tailwind 指定 svg 颜色类名 fillClass: { type: String } }) const symbolId = computed(() => `#icon-${props.name}`) </script>
全局注册
import { defineAsyncComponent } from 'vue' /** * 如果要用插件 要有install方法 */ export default { install: function (app) { const components = import.meta.glob('./*/index.vue') for (const [fullPath, fn] of Object.entries(components)) { const componentName = 'm-' + fullPath.replace('./', '').split('/')[0] app.component(componentName, defineAsyncComponent(fn)) } } }
// 注册svg-icon 虚拟前缀
import 'virtual:svg-icons-register'
<m-svg-icon v-if="loading" name="loading" class="w-2 h-2 animate-spin mr-1" ></m-svg-icon>
如果直接使用
img src=""
或者第三方库