一、icon组件
在项目中,会用到两种图标:element-plus自带图标和自定义图标
编写自定义组件展示自定义svg图标,这是一种通用方案
二、创建svgIcon组件
1.组件接受两个prop:icon和className
按需引入defineProps来定义接受的prop
import { defineProps, computed } from 'vue'
// vue3 中defineProps用来接收props
const props = defineProps({
// icon路径
icon: {
type: String,
required: true
},
// 图标类名
className: {
type: String,
default: ''
}
})
2.需要三个计算属性:
(1)是否是外部图标
根据icon是否为http(s),tel,mailto开头来判断是否为外部图标,可以封装一个工具函数
export function isExternal(path) {
/**
* param path 资源路径
*/
return /^(https?:|mailto:|tel:)/.test(path)
}
(2)外部图标样式
<template>
<div>
<!-- 展示外部图标 -->
<div
v-if="isExternal"
:class="className"
:style="externalIconStyles"
class="svg-external-icon svg-icon"
></div>
<svg v-else :class="className" class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
<!-- 展示内部图标 -->
</div>
</template>
(3)内部图标名
import { defineProps, computed } from 'vue'
import { isExternal as isExternalValidation } from '@/utils/validate'
// vue3 中defineProps用来接收props
const props = defineProps({
// icon路径
icon: {
type: String,
required: true
},
// 图标类名
className: {
type: String,
default: ''
}
})
// 需要一些计算属性
/**
* 内部图标
*/
/**
* 外部图标样式
*/
/**
* 判断是否为外部图标
*/
// 判断一个资源是否为内部资源是一个常用方法,可以封装为一个工具
const isExternal = computed(() => isExternalValidation(props.icon))
// 外部图标样式
const externalIconStyles = computed(() => ({
mask: `url(${props.icon}) no-repeat 50% 50%`,
'webkit-mask': `url(${props.icon}) no-repeat 50% 50%`
}))
// 内部图标添加一个统一前缀
const iconName = computed(() => `#icon-${props.icon}`)
三、图标显示
1.外部图标显示
外部图标用div标签,给div绑定mask属性便可显示svg
{
mask: `url(${props.icon}) no-repeat 50% 50%`,
'webkit-mask': `url(${props.icon}) no-repeat 50% 50%`
}
2.内部图标
require.context
多个内部图标需要先注册,使用webpack的require.context方法可以创建一个上下文(返回一个require函数),可以自动导入某个文件下多个子文件,不用重复调用import
require.context(
directory,
(useSubdirectories = true),
(regExp = /^\.\/.*$/),
(mode = 'sync')
);
require函数
返回的require函数有三个属性,还可以接收一个request参数这里主要用到了函数的keys方法(返回相对文件名路径)
(1)将路径作为request参数传入require函数进行svg导入
(2)引入svg-icon进行全局注册
// 导入所有svg图标
// 将SvgIcon组件进行全局注册
import SvgIcon from '@/components/svgIcon/index.vue'
const svgRequire = require.context('./svg', false, /\.svg$/)
// svgRequire 是一个函数,接受一个request参数,该函数有三个属性
/**
* resolve 函数,返回request被解析后得到的模块id
* keys 函数,返回文件数组,这里返回svg图标
* id 返回context module的id
*/
// 将svgRequire.keys返回的的文件名作为request参数传入svgRequire,进行图标注册
svgRequire.keys().forEach((svgIcon) => svgRequire(svgIcon))
export default (app) => {
app.component('svg-icon', SvgIcon)
3.svg-sprite-loader
使用内部图标后,无法显示,是因为项目中不能处理svg的loader
(1)安装loader
cnpm i svg-sprite-loader@6.0.9 --save--dev
(2)添加配置
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
chainWebpack(config) {
// 设置 svg-sprite-loader
config.module.rule('svg').exclude.add(resolve('src/icon')).end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/icon'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
}