Vue使用svg-sprite-loader自动引入svg图标 [自己遇到的问题解决]
我使用的vue + ts. 内容中包含ts 和 js 两个版本的代码.
我是在网上看到了在vue 中优雅的使用 svg 的文章, 就想学习使用一下, 但是自己在使用的时候遇到了问题, 问题已经解决, 分享一下使用方法, 我遇到的问题, 解决办法.
写完之后发现写的可能有些啰嗦 😂
我的项目目录
现在未配置之前使用 svg
1. 安装 svg-sprite-loader
npm i svg-sprite-loader -S
2. 在 vue.config.js
中配置 svg-sprite-loader
可以使用 vue inspect --rule svg
查看当前 svg 的处理规则
vue inspect 的简单使用可以戳这里
vue.config.js 配置
这是我的 vue.coonfig.js 文件的配置 (只配置了svg相关的
// vue.config.js
const path = require('path')
const resolve = dir => path.join(__dirname, dir)
module.exports = {
chainWebpack: config => {
// 1. 取消默认 file-loader 对 svg 文件的处理
config.module
.rule('svg') // 对 svg 规则的配置
.exclude // 添加忽略文件夹, 忽略file-loader对这个文件夹下的svg文件处理
// 建议使用绝对路径
// .add('./src/assets/icons/svg') // 相对路径
.add(resolve('./src/assets/icons/svg')) // 绝对路径
.end()
config.module
.rule('icons') // 配置 icons 的规则
.test(/\.svg$/) // 匹配以 .svg 结尾的文件
.include // 添加要处理的文件夹
.add(resolve('./src/assets/icons/svg'))
.end()
.use('svg-sprite-loader') // 使用 svg-sprite-loader 处理
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]' // 配置 symbol id, 需要使用这个 id 来使用 svg 图标
})
.end()
}
}
为什么我要使用绝对路径
我看着网上教程配置的时候都是使用的相对路径, 但是我使用的时候却出现了错误, 报错exclude配置的路径不是一个绝对路径
配置之后再可以查看是否配置成功
配置完成之后记得重新启动项目.
配置成功就可以在页面中 引入svg并使用
并且 原来使用 img 标签显示不出来
当然在每个页面都要引入svg会很麻烦. 下面配置自动引入和 svg 组件
3. 配置自动引入svg, 配置完成之后只需要下载svg -> 把 svg 文件放到指定文件夹中就可以直接使用.
根据自己的项目目录在新建 一个js 文件. 我是在 icons 下面新建了 indes.ts (我使用的ts
文件
文件内容:
// index.ts
// require.context 可以获取到项目目录中的文件.
// require.context(路径, 是否递归子文件夹, 要处理什么文件)
const req: any = require.context('./svg', false, /\.svg$/)
req.keys().map(req) // 得到的是文件路径<处理后路径 /img开头>的数组
在 main.js
中引入此文件就会自动处理指定文件夹下的所有 .svg 文件
4. 封装一个 svg-icon
组件
在 src/components
路径下新建 svg-icon
组件
.ts 版本
// ts 版本
<template>
<svg
:class="svgClass"
aria-hidden="true"
>
<use :xlink:href="iconName"></use>
</svg>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
@Component
export default class IconSvg extends Vue {
@Prop({ required: true }) private iconClass!: string
private name: string = 'icon-svg'
private data(): object {
return {
isCommon: true,
}
}
public get iconName() {
return `#icon-${this.iconClass}`
}
public get svgClass() {
return this.iconClass ? 'svg-icon ' + this.iconClass : 'svg-icon'
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
.js 版本
<template>
<svg
:class="svgClass"
aria-hidden="true"
>
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
}
},
computed: {
iconName () {
return `#icon-${this.iconClass}`
},
svgClass () {
return this.iconClass ? 'svg-icon ' + this.iconClass : 'svg-icon'
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
全局注册此组件即可使用.
5. 自动注册组件
我配置了自动注册组件, 分享一下.
我在components下新建了 component.ts
.ts版本
import { Vue } from 'vue-property-decorator'
const files: any = require.context('./', true, /\.vue$/)
const components: any = {}
files.keys().forEach((key: string) => {
try {
const str = key.match(/[^/]+$/)![0].replace(/\.vue$/, '')
// 如果组件的data中有 isCommon 就代表是全局注册的组件.
if (files(key).default.extendOptions.data().isCommon) {
components[str] = files(key).default
}
} catch { }
})
// 全局注册组件, 我组件名称使用的是大驼峰写法, SvgIcon 注册后使用 <svg-icon />
Object.keys(components).forEach((key: string) => {
Vue.component(key, components[key])
})
.js 版
import Vue from 'vue'
const files = require.context('./', true, /\.vue/)
files.keys().forEach(filePath => {
const component = files(filePath).default
// 组件注册的时候可以使用 name. 我的ts中使用的是文件名.
Vue.component(component.name, component)
})