npm install svg-sprite-loader
注意:
如果按照下面配置正确发现svg依然无法显示可能s’v’g-sprite-loader的版本过高,重新指定版本下载npm i [email protected] --save-dev, 就可能正确显示svg。(vue3.0应该是没有这个问题的)
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/assets/icons')],
options: {
symbolId: 'icon-[name]'
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',//给图片资源配置路径加载器,用于文件抽离
exclude: [resolve('src/assets/icons')],
options: {
name: '[name][hash:5].[ext]',//设置抽离打包图片的名称--[ext]用来获取图片的后缀
limit: 100000,//限制图片大小 <= 100kb 进行base64编码(小于100kb打包进js文件)--测试时根据图片的大小调整
outputPath: 'image'//设置输出文件夹名称,这个文件夹会与主入口文件在同一路径下
}
},
如果只需要引入一个图标,可以手动引入这个图标
<template>
<div class="twoPage">
<svg class="svg-icon" aria-hidden="true">
<use xlink:href="#icon-404" />
</svg>
</div>
</template>
<script>
import '../assets/icons/404.svg'
export default {
data() {
return {};
},
};
</script>
<style lang="less">
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
如果引入的svg比较多,手动一个一个引入就比较麻烦,而且没必要
svgRequire.js
//引入文件夹中的所有.svg 结尾的文件
export function requireAllContext(){
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
return requireAll(req)
}
// 遍历文件夹内子目录,并且引入所有子目录的名字
export function icons(){
const req = require.context('../../assets/icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const icons = requireAll(req).map(i => {
return i.match(re)[1]
})
return icons
}
<template>
<div class="twoPage">
<div class="svgBox">
<div class="svgItem" v-for="item in iconList" >
<svg class="icon" aria-hidden="true">
<use :xlink:href="'#icon-'+item"></use>
</svg>
<span>{{item}}</span>
</div>
</div>
</div>
</template>
<script>
import {requireAllContext, icons} from '../assets/js/svgRequire'
export default {
data() {
return {
iconList:[]
};
},
created(){
//引入所有svg图标内容
requireAllContext()
//引入所有图标的名称
this.iconList = icons()
},
};
</script>
<style lang="less">
.twoPage{
height: 800px;
.svgBox{
width: 500px;
height: 300px;
overflow: auto;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
.svgItem{
width: 80px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
svg{
width: 20px;
height: 20px;
}
}
}
}
</style>
<!-- 表单输入框 -->
<el-input slot="reference" v-model="addMenuForm.remark" placeholder="点击选择图标" readonly>
<span slot="prefix" v-if="addMenuForm.remark" >
<svg class="svg-icon" aria-hidden="true" style="height: 41px;width: 16px;">
<use :xlink:href="'#icon-'+addMenuForm.remark" />
</svg>
</span>
<i slot="prefix" class="el-input__icon el-icon-search" v-else></i>
</el-input>
html
<el-form-item label="菜单图标" prop="remark">
<el-popover placement="bottom-start" width="400" trigger="click" class="menuAddSvg">
<el-input slot="reference" v-model="addMenuForm.remark" placeholder="点击选择图标" readonly>
<span slot="prefix" v-if="addMenuForm.remark" >
<svg class="svg-icon" aria-hidden="true" style="height: 41px;width: 16px;">
<use :xlink:href="'#icon-'+addMenuForm.remark" />
svg>
span>
<i slot="prefix" class="el-input__icon el-icon-search" v-else>i>
el-input>
<div class="icon-body">
<el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @keyup.native="keyUpSvg(name)">
<i slot="suffix" class="el-icon-search el-input__icon" />
el-input>
<div class="icon-list">
<div v-for="(item, index) in iconList" :key="index" @click="checkSvg(item)">
<svg class="svg-icon" aria-hidden="true" style="height: 30px;width: 16px;">
<use :xlink:href="'#icon-'+item" />
svg>
<span>{{ item }}span>
div>
div>
div>
el-popover>
el-form-item>
js:
通过document.body.click()
关闭el-popover
的弹窗
//模糊搜索选择svg
keyUpSvg(item){
let list = this.iconAllList.filter(icon => {
return icon.indexOf(item)>-1
})
this.iconList = list
},
//选择svg
checkSvg(item){
this.addMenuForm.remark = item;
document.body.click()
}
created(){
this.iconList = icons();
this.iconAllList = icons();//备份一个完整的数据,避免后面输入框清空,iconList为空数组后,没有完整数据
}
css:
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.icon-body {
width: 100%;
padding: 10px;
.icon-list {
height: 200px;
overflow-y: scroll;
div {
height: 30px;
line-height: 30px;
margin-bottom: -5px;
cursor: pointer;
width: 33%;
float: left;
}
span {
display: inline-block;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
}
}
我也是使用的时候感觉上面的方法还是有些麻烦,有的页面如果需要两三个svg图标的时候,要么在当前页面把所有svg都引入进来,要么手动一个一个引入图标。像下面这样,就很恶心!!!!
所以我们需要把所有的svg引入到全局,通过main.js引入一下,那样整个项目都可以用了这些svg,随时可取用。
直接调用引入svg文件夹内的.svg文件,而不是写成方法,方法必须指定页面调用才在指定页面成效。
//引入文件夹中的所有.svg 结尾的文件
// export function requireAllContext(){
// const req = require.context('./svg', false, /\.svg$/)
// const requireAll = requireContext => requireContext.keys().map(requireContext)
// return requireAll(req)
// }
// 1.
//上面的方法是需要在指定的页面的调用这个方法,才能获取到svg。
//下面的方法是直接调用获取svg,后面在main.js里面直接引入这个Index.js即立即调用
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
// 2.遍历文件夹内子目录,并且引入所有子目录的名字
export function icons(){
const req = require.context('../../assets/icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const icons = requireAll(req).map(i => {
return i.match(re)[1]
})
return icons
}
// 3.全局挂载SvgIcon组件
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component
Vue.component('svg-icon', SvgIcon)
引入icons文件夹内的index.js
import './assets/icons'
<svgIcon icon="component"></svgIcon>