背景
一般html中使用svg图片是用img标签使用,这在项目中就相对来说非常麻烦。出现大量使用svg情况就变的比较麻烦
<img src="../assets/svgs/car.svg" />
封装
将svg文件统一放一个文件夹下 src/assets/svgs
需要2步
为文件打包
安装开发依赖
npm i svg-sprite-loader -D
打包配置
....
chainWebpack: config => {config.module.rule('svg').exclude.add(resolve('src/assets/svgs')).end()config.module.rule('icons').test(/\.svg$/).include.add(resolve('src/assets/svgs')).end().use('svg-sprite-loader').loader('svg-sprite-loader').options({symbolId: 'icon-[name]'}).end()},
....
或
...
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({chainWebpack: (config) => {const svgRule = config.module.rule('svg')svgRule.uses.clear()// 添加要替换的 loadersvgRule.use('svg-sprite-loader').loader('svg-sprite-loader').options({symbolId: 'icon-[name]'})}})...
为开发
封装VSvg.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, importAll } from '@/utils/util'importAll(require.context('@/assets/svgs', false, /\.svg$/))export default {name: 'VSvg',props: {icon: {type: String,required: true},className: {type: String,default: ''}},computed: {isExternal () {return isExternal(this.icon)},iconName () {return `#icon-${this.icon}`},svgClass () {if (this.className) {return 'svg-icon ' + this.className} else {return 'svg-icon'}},styleExternalIcon () {return {mask: `url(${this.icon}) no-repeat 50% 50%`,'-webkit-mask': `url(${this.icon}) 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>
util.js
export function isExternal (path) {return /^(https?:|mailto:|tel:)/.test(path)
}export function importAll (requireContext) {requireContext.keys().forEach(requireContext)
}
关于require.context方法
核心就是使用了webpack内置的require.context方法
详细参数解释点击这里官网传送门
require.context(directory, //这里指存放svg文件目录的路径(useSubdirectories = true), //是否还搜索其子目录,默认为true(regExp = /^\.\/.*$/), //正则匹配文件类型, 这里我们匹配 .svg 结尾的文件 /\.svg$/(mode = 'sync') //模式,默认同步
);
main中注册
import VSvg from '@/components/base/VSvg.vue'
import Vue from 'vue'Vue.component('v-svg', VSvg)
由于此处我注册的组件较多,而且都在一个文件里面
const registerGlobal = (Vue) => {const requireComponent = require.context('@/components/base', true, /\.vue$/)console.log('学习', requireComponent)requireComponent.keys().forEach(fileName => {const componentConfig = requireComponent(fileName)const Component = componentConfig.default || componentConfigconst componentName = kebabCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))if (typeof Component.install === 'function') {Vue.use(Component)} else {Vue.component(componentName, Component)}})Vue.directive('perm', hasPerm)Vue.filter('dayjs', (val, formatter = 'YYYY-MM-DD HH:MM:ss') => dayjs(val).format(formatter))
}
组件使用
<v-svg icon="zoom-out" />