51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Vue Icon 图标处理方案

Preface {#preface}

在 Vue 前端项目中不可避免的要使用 icon svg 图标组件,对于这个组件它需要两种能力:

  1. 显示外部 svg 图标。
  2. 显示项目内的 svg 图标。

基于以上概念,我们先来实现显示外部 svg 图标。

显示外部 svg 图标 {#显示外部-svg-图标}

  1. 首先在项目中创建 src/components-global/svg-icon/index.vue,编写如下代码:
<template>
  <div
    v-if="isExternal"
    :style="styleExternalIcon"
    class="svg-external-icon svg-icon"
    :class="className"
  />
</template>

<script setup> import { defineProps, defineOptions, computed } from 'vue'

defineOptions({ name: 'SvgIcon' })

const props = defineProps({ // icon 图标 icon: { type: String, required: true }, // 图标类名 className: { type: String, default: '' }, // 同时设置宽度和高度 size: { type: String }, // 宽度 width: { type: String, default: '1em' }, // 高度 height: { type: String, default: '1em' } })

/**

  • 判断是否为外部图标 / const isExternal = computed(() => { return /^(https?:|http?|mailto:|tel:)/.test(props.icon) }) /*
  • 外部图标样式 / const styleExternalIcon = computed(() => ({ / 在 CSS 中,mask 属性用于定义图像蒙版或剪切蒙版。 它允许您通过指定一个图像或 SVG 元素作为另一个元素的蒙版来创建复杂的视觉效果。 mask 属性通过根据蒙版的透明度值隐藏元素的部分来实现。 */ mask: url(${props.icon}) no-repeat 50% 50%, '-webkit-mask': url(${props.icon}) no-repeat 50% 50%, // 设置宽高 width: props.size ?? props.width, height: props.size ?? props.height })) </script>

<style scoped> .svg-icon { vertical-align: -0.15em; fill: currentColor; overflow: hidden; }

.svg-external-icon { background-color: currentColor; mask-size: cover !important; display: inline-block; } </style>

  1. 编写完成之后,我们在 App.vue 使用:http://res.lgdsunday.club/user.svg这个链接来测试外部 svg 图标是否引用成功。
<template>
  外部图标测试:<svg-icon icon="http://res.lgdsunday.club/user.svg" />
</template>

<script setup> import SvgIcon from '@/components-global/svg-icon'

</script>

<style lang="scss"></style>

显示效果如下:

image-20231115120229537

显示内部 svg 图标 {#显示内部-svg-图标}

  1. 首先需要准备一些 svg 图标文件,可以从iconfont-阿里巴巴矢量图标库中下载,下载完成之后放到项目中的src/assets/icons/svg目录下。

image-20231115144325267

  1. 创建 src/assets/icons/index.js
import SvgIcon from '@/components-global/svg-icon'

/* https://webpack.docschina.org/guides/dependency-management/#requirecontext require.context 是一个在 Webpack 中用于创建模块上下文的函数。 它的主要作用是实现动态地导入模块,特别是用于导入一组符合特定规则的模块。 通常,它用于在前端项目中处理导入大量模块或文件的情况,例如导入所有的图片、样式文件或特定目录下的组件。

require.context 接受三个参数: 1. 要搜索的目录:一个字符串,表示要搜索的目录路径。 2. 是否搜索其子目录:一个布尔值,表示是否要搜索指定目录的子目录。 3. 匹配文件的正则表达式:一个正则表达式,用于匹配文件名。

使用 svgContext.keys() 获取所有匹配的文件路径,然后通过 svgContext(svgIcon) 来动态导入每个 SVG 文件 */ const svgContext = require.context('./svg', false, /.svg$/) svgContext.keys().forEach(svgIcon => svgContext(svgIcon))

export default Vue => { // 这里为什么将变量名设置为 Vue 呢?请参考:https://juejin.cn/post/7114133835339530276 Vue.component('svg-icon', SvgIcon) }

  1. main.js 中引入该文件。
...
// 导入 SvgIcon
import installIcons from '@/assets/icons'

... // 安装 svg 图标和注册 SvgIcon 组件 installIcons(app) ...

  1. 使用 svg-sprite-loader 处理 svg 图标

svg-sprite-loaderwebpack 中专门用来处理 svg 图标的一个 loader

下载该 loader,执行:npm i --save-dev svg-sprite-loader

创建 vue.config.js 文件,新增如下配置:

const { defineConfig } = require('@vue/cli-service')

const path = require('path')

/**

  • __dirname 是当前执行脚本文件的目录,
  • 因此 resolve 函数会将相对路径与该目录拼接,返回一个绝对路径。 */ const resolve = (dir) => { return path.join(__dirname, dir) }

// https://cli.vuejs.org/zh/guide/webpack.html module.exports = defineConfig({ chainWebpack (config) { /* 配置 svg-sprite-loader 来处理 SVG 图标,将多个独立的SVG图标文件打包成一个单独的SVG精灵图(SVG sprite) 1. 设置排除规则(exclude)和包含规则(include): 1.1 config.module.rule('svg') 定义了一个规则,用于处理所有以 .svg 结尾的文件, 但它通过 .exclude.add(resolve('src/assets/icons')) 来排除了 src/assets/icons 目录下的 SVG 文件。 这意味着 src/icons 目录下的 SVG 文件不会被该规则处理,而是由下面的规则单独处理。 1.2 config.module.rule('icons') 定义了一个规则,用于处理 src/icons 目录下的 SVG 文件,通过 .include.add(resolve('src/assets/icons')) 来指定只处理该目录下的文件。 2. 使用 svg-sprite-loader: 2.1 通过 .use('svg-sprite-loader') 来配置使用 svg-sprite-loader 作为处理 SVG 文件的 loader。 2.2 通过 .loader('svg-sprite-loader') 指定加载器的名称为 svg-sprite-loader。 2.3 使用 .options({ symbolId: 'icon-[name]' }) 来配置 svg-sprite-loader 的选项,其中 symbolId 用于定义每个 SVG 符号的标识,通常在 SVG 精灵图中使用。 */ config.module .rule('svg') .exclude.add(resolve('src/assets/icons')) .end() config.module .rule('icons') .test(/.svg$/) .include.add(resolve('src/assets/icons')) .end() .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({ symbolId: 'icon-[name]' }) .end() } })

  1. 编写完成之后,我们在 App.vue 使用第一步导入的 头像 男孩.svg 文件进行测试。
<template>
  内部图标测试:<svg-icon icon="头像 男孩" size="28px" />
</template>

<style lang="scss"></style>

显示效果如下:

image-20231115144558886

至此一个可以引用外部和内部 svg 图标的 SvgIcon 组件封装完毕。

参考资料 {#参考资料}

赞(5)
未经允许不得转载:工具盒子 » Vue Icon 图标处理方案