前言🌴🌴
在项目开发的过程中,我们会使用到大量的SVG图标,那么如果我们在项目中直接进行引用这样就太不方便,今天就来讲一下如何封装一个支持本地 SVG 图标和在线 SVG 图标的组件 svg-icon。
什么是SVG图标?🥝🥝
简介:SVG
是一种可伸缩的矢量图型(就是用标签代码来画图),它基于XML并用于描述图形的语言;如果我们通过vscode打开SVG
图片,会发现他是基于一大串代码实现的。这和其他图片是以像素来描绘的不一样。
- 不同于用像素来描绘的矩阵图像(JPG、PNG、GIF),
SVG
是和分辨率无关,也就是说,他和其他图片不同的地方就在于他放大也不会失真,图片依旧保持清晰。; SVG
图像可以通过JS和DOM操作来创建和操控;SVG
有自己庞大的语法和较大的复杂度,我们这里只是了解下有这种图像格式;
在本地引入一些svg图标 🍂🍂
介绍一下require.context
在接下来的工作开始之前,首先要介绍一下要使用到的API:
require.context方法进行简介:
他其实是一个webpack
的API,获取一个特定的上下文,主要用来实现自动化导入模块。
使用场景:如果遇到从一个文件夹引入很多模块的情况,可以使用这个API,它会遍历文件夹中的指定文件,然后自动导入,使得不需要每次显式的调用import导入模块
接收三个参数:require.context(directory,useSubdirectories,regExp)
directory
这个参数表明要检索的目录useSubdirectories
传入一个布尔值,表明是否检索子文件regExp
匹配的正则表达式,一般是文件名
值得注意的是require.context函数执行后返回的是一个函数,并且这个函数有3个属性,我们重点了解其中的一个
- keys {Function} -返回匹配成功模块的名字组成的数组
开始配置
首先在src下面创建icons文件夹,在src/icons里面创建svg文件夹,在svg文件夹中引入svg图片,
同时在svg文件夹的平级创建index.js文件
然后在index.js文件中进行一些配置:
- 首先引入SvgIcon这个组件
- 然后使用require.context函数,返回一个函数,定义为svgRequire
- 然后通过遍历
svgRequire.keys()
来获取匹配的svg路径 - 注意返回的svgRequire函数接收一个参数,用于指定要导入的文件路径。通过在循环中调用
svgRequire(svgIcon)
,我们将每个图标文件路径作为参数传递给这个导入函数,以完成对每个图标文件的导入操作。 - 具体来说,这些导入的图标文件将被 webpack 处理,并根据配置将它们打包到最终生成的 JavaScript bundle 中。
- 当你在应用程序的其他组件中使用
<svg-icon>
组件时,实际上是在使用已导入到 JavaScript bundle 中的 SVG 图标模块。这些图标模块可以根据需要在运行时动态加载和渲染。 - 因此我们还需要进行一些webpack的配置
import SvgIcon from '@/components/SvgIcon'; // 使用这个api来完成导入 // https://webpack.docschina.org/guides/dependency-management/#requirecontext const svgRequire = require.context('./svg', false, /.svg$/); svgRequire.keys().forEach((svgIcon) => { svgRequire(svgIcon); }); // 完成全局注册,这里传入的是main.js中创建的app实例 export default (app) => { app.component('svg-icon', SvgIcon); };
如何封装svg组件 🐤🐤
首先我们需要在scr/component下面创建一个SvgIcon文件夹,并在里面创建一个index.vue文件
接下来我们要在创建的文件中写入下面的代码。
定义props部分
首先定义props,这里面我选择的是Vue3的setup语法糖的书写形式,这个props接收两个参数,一个icon就是要接受的icon图标的名字,当然,这个图标名称还要后续的进一步加工,也就是说,iconName是真正的名称,之所以要这么做是因为等一会需要进行配置项处理。另一个className是传递过来的icon的类名。
const props = defineProps({ icon: { type: String, required: true }, // 图标类名 className: { type: String, default: '' } }); // 项目内部图标,就相当于是一个名称 const iconName = computed(() => `#icon-${props.icon}`);
因为我们这个组件不仅要实现能够内部引用SVG图标还要能够引用外部的SVG图标(比如阿里的图标库),所以我们要进行一个判断该图标是否为外部引用的。
const isExternal = computed(() => external(props.icon)); ------------------------------- // 判断是否是外部图标 export function isExternal(path) { // 判断是否是这几个开头,如果是的话那么就是外部图标 return /^(https?:|http)/.test(path); }
这里面我进行了一个简单的判断,如果是以http或者https开头的,那么就认为这个SVG图标是从网站引用的,是一个在线的SVG图标。
HTML部分
下面这部分是进行简单的HTML处理,如果是外链的SVG图标就显示第一个,如果是项目内部的图标那就显示下面的
<template> <!-- 判断是否为外部图标 --> <div v-if="isExternal" :style="styleIsExternalIcon" class="svg-icon svg-external-icon" :class="className" ></div> <!-- 内部图标 --> <svg v-else class="svg-icon" :class="className" aria-hidden="true"> <use :xlink:href="iconName"></use> </svg> </template>
在这里使用了HTML中的svg标签,首先我们要先介绍一下svg标签:
- SVG 代码以
<svg>
元素开始,包括开启标签<svg>
和关闭标签</svg>
- width 和 height 属性可设置此 SVG 文档的宽度和高度
- version 属性可定义所使用的 SVG 版本,xmlns 属性可定义 SVG 命名空间。
那么这里的use又是什么呢?
- 标记的作用是能从SVG文档内部取出一个节点,克隆它,并把它输出到别处。跟‘引用’很相似,但它是深度克隆
- 比如你在同一个svg中定义了一个矩形元素:
<rect id="myRect" width="100" height="50" />
然后你想要在进行复用,那么你就可以使用use标签:
<use xlink:href="#myRect" />
这里面的xlink:href
属性后面引用的图形元素的唯一标识符(通常是该元素的id
属性的值)
简单的样式处理
// 外部图标的样式 const styleIsExternalIcon = computed(() => ({ mask: `url(${props.icon}) no-repeat 50% 50%`, '-webkit-mask': `url(${props.icon}) no-repeat 50% 50%` }));
引入插件并进行配置项处理🚴♀🚴♀
在进行完上面的处理之后,我们发现还是无法正常的显示svg图标,这是为什么呢?
我们还需要安装一个插件
npm i --save svg-sprite-loader
- SVG雪碧图生成:它将多个独立的SVG文件合并为一个SVG雪碧图,即将每个SVG图标放在一个共享的SVG容器中,从而减少HTTP请求的数量。这种合并使得加载和渲染多个SVG图标变得更加高效。
- 自动生成模块:插件会为每个SVG图标生成一个模块,并导出一个包含图标的使用代码。这样,可以像导入其他模块一样导入这些SVG图标模块,并直接在应用中使用它们。这简化了SVG图标的使用和管理。
- 图标的使用:在应用程序中,您可以通过使用导入的SVG图标模块的默认导出来使用图标。这样,您可以直接在HTML、CSS或JavaScript中引用图标,而无需将每个图标作为单独的文件引入
可以打开官网进行参考
VueCli官网的配置
module.exports = defineConfig({ chainWebpack(config) { config.module // 规则 .rule('svg') .exclude.add(resolve('src/icons')).end(); config.module // 规则 .rule('icons') // 正则,解析 .svg格式文件 .test(/.svg$/) // 解析的文件 .include.add(resolve('src/icons')).end() // 新增了一个解析的loader .use('svg-sprite-loader') //具体的loader .loader('svg-sprite-loader') .options({ symbolId: 'icon-[name]' }) .end(); } })
注意这个options中的symbolId,这一部分就是我们对svg图标的名称定义,这也是svg-sprite-loader这个插件所需要的,使用"icon-[name]",其中的name就是具体的svg图标名称。
我们在vue.config中进行配置,通过使用webpack中的exclude和include来指定要处理的路径,同时我们添加了一些处理规则,使用了正则表达式来解析指定的文件。
进行使用
<span class="svg-container"> <svg-icon icon="user" /> </span>
这样就完成了本地svg图片的导入
总结😄😄
这次学习了如何对项目中的SVG图标进行一个组件封装,掌握了许多之前没有学习到的知识,感觉收获满满