首先需要安装svg-sprite-loader依赖,命令如下,这在在学习的过程中,就是因为没有下载该依赖,导致图标一直无法正常显示。
npm install svg-sprite-loader --save-dev --force
通过使用svg-sprite-loader组件,将svg的图标文件生产雪碧图(Sprite),在vue.config.js文件中进行配置,具体如下:
//用于导入Node.js核心模块 path 的方法。path 模块提供了处理文件路径的实用工具,可以用于处理和操作文件路径字符串。
const path = require('path')
//定义了一个名为 resolve 的函数,用于将相对路径转换为绝对路径。__dirname 是 Node.js 中的一个全局变量,表示当前模块文件所在的目录的绝对路径。
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
lintOnSave: false,
transpileDependencies: ["vue"],
publicPath: '/sys', // 设置上下文路径,与Tomcat或Nginx中的上下文路径保持一致
indexPath: 'index.html', // 相对于打包路径index.html的路径
outputDir: 'sys', // 'dist', 生产环境构建文件的目录
productionSourceMap: true,
devServer: {
port: 8881,
headers: {
'Access-Control-Allow-Origin': '*',
}
},
chainWebpack(config) {
//覆盖默认配置中处理svg的规则
config.module
.rule('svg')//定义规则名称,必须为svg,为了覆盖该规则
.exclude.add(resolve('src/components/SvgIcon'))
.end()
//定义处理指定目录下svg图片的规则
config.module
.rule('icons1')//定义规则名称,可以自定义
.test(/\.svg$/)//表示该规则只适用于后缀为 .svg 的文件。
.include.add(resolve('src/components/SvgIcon'))//只对这个目录下的SVG文件应用该规则。
.end()
.use('svg-sprite-loader')// 指定了使用 svg-sprite-loader 这个loader来处理满足该规则的SVG文件。
.loader('svg-sprite-loader')//指定了要使用的loader为 svg-sprite-loader。
.options({//对 svg-sprite-loader 的配置选项,通过 symbolId 可以设置每个图标的标识符,这里使用 icon-[name] 表示使用图标文件的名称作为标识符。
symbolId: 'icon-[name]'
})
.end()
}
};
雪碧图(Sprite)是一种将多个小图标或图片合并到一个大图中的技术。通过将多个图标放置在同一张图上,并通过CSS的background-position属性来控制显示不同的图标位置,可以减少网络请求次数,提高页面加载速度和性能。
svg-icon组件包括了svg文件(svg图片)、index.vue和index.js三部分内容。其中,svg文件,主要包括了各个图标对应的svg文件,上述vue.config.js文件中的配置,就是将该文件下的文件生成雪碧图;index.vue用来定义图标的vue组件;index.js实现了svg-icon组件的注册。具体实现如下:
index.vue页面,代码如下:
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" />
svg>
template>
<script>
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
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>
index.js文件,代码如下:
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon/index.vue'// svg component
// 注册
Vue.component('svg-icon', SvgIcon)
//在当前文件所在目录下的 ./svg 目录中查找所有以 .svg 结尾的文件,并将匹配的文件创建一个模块上下文
const req = require.context('./svg', false, /\.svg$/)
//将模块上下文中的所有模块导入,并注册为SvgIcon组件的子组件。
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
这里实现了一个展示全部svg图标的页面,包括了svg-icons.js文件和index.vue文件,其中,svg-icons.js主要读取所有的svg图标的名称;index.vue定义了展示图标的页面。
svg-icons.js代码实现如下,类似上述index.js文件,读取文件目录,获取文件名称:
const req = require.context('../SvgIcon/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const svgIcons = requireAll(req).map(i => {
return i.match(re)[1]
})
console.log(svgIcons);
export default svgIcons
index.vue页面代码实现如下:
<template>
<div class="icons-container">
<el-tabs type="border-card">
<el-tab-pane label="Icons">
<div v-for="item of svgIcons" :key="item">
<el-tooltip placement="top">
<div slot="content">
{{ generateIconCode(item) }}
div>
<div class="icon-item">
<svg-icon :icon-class="item" class-name="disabled" />
<span>{{ item }}span>
div>
el-tooltip>
div>
el-tab-pane>
el-tabs>
div>
template>
<script>
import svgIcons from './svg-icons'
export default {
name: 'Icons',
data() {
return {
svgIcons
}
},
methods: {
generateIconCode(symbol) {
return `${symbol} " />`
}
}
}
script>
<style lang="scss" scoped>
.icons-container {
margin: 10px 20px 0;
overflow: hidden;
.icon-item {
margin: 20px;
height: 85px;
text-align: center;
width: 100px;
float: left;
font-size: 30px;
color: #24292e;
cursor: pointer;
}
span {
display: block;
font-size: 16px;
margin-top: 10px;
}
.disabled {
pointer-events: none;
}
}
style>