封装SvgIcon组件总结

前言

最近维护一个vue3项目,svg文件要么使用img图片导入,要不之间写在代码里面,感觉非常不优雅,img加载过多也会使得网站体验非常不友好,于是打算把svg文件加载封装成一个组件,提升使用体验。

封装SvgIcon

1. SvgIcon.vue组件封装

xml 复制代码
<template>
  <svg
    class="svg-icon"
    :class="className"
    aria-hidden="true"
    :width="width"
    :height="height"
  >
    <use :href="iconName" />
  </svg>
</template>
<script lang='ts' setup>
import { computed } from 'vue';

const props = defineProps({
    icon: {   // svg图片是啥子名字,这个icon就传递啥子名字,例如"arrowDown \ arrowUp"
        type: String,
        required: true
    },
    // 图标类名
    className: {
        type: String,
        default: ''
    },
    width: {
      type: [Number, String],
      default: ""
    },
    height: {
      type: [Number, String],
      default: ""
    }
});
// 项目内部图标,就相当于是一个名称
const iconName = computed(() => `#icon-${props.icon}`);

</script>
<style lang='scss' scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  fill: currentColor; // 继承文本颜色
}
</style>

组件就是封装了一个svg标签,加几个传参,很简单的样子,让我们一一解读下。

1.1 icon传参有啥作用?

icon传参为svg文件名称,#icon-${props.icon} 是一个svg的唯一ID,取"icon-"加svg文件名组合的字符串来生成这个ID,只有拿到了这个ID,我们的use标签的href才能将SVG文件复制到当前封装的这个组件所在的位置里。

1.2 组件里面的use标签有啥用呢 ?

<use> 元素从 SVG 文档中获取节点,并将它们复制到其他地方。其效果与将这些节点深度克隆到一个不可导出的 DOM 中,然后粘贴到 use 元素所在的位置相同,这与克隆的模版元素类似。 我们参考如下MDN给的示例,svg中circle有一个id, 我们想复制circle标签到其他两个use标签拿,直接用use的herf属性指向这个id, 即href="#myCircle"就能拿到复制的circle标签了!

ini 复制代码
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="5" cy="5" r="4" stroke="blue" />
  <use href="#myCircle" x="10" fill="blue" />
  <use href="#myCircle" x="20" fill="white" stroke="red" />
</svg>
1.3 样式设置
  • width: 1em; height: 1em; :使图标大小与父元素的字体大小一致
  • fill: currentColor; :使图标颜色继承父元素的文本颜色

2 将SvgIcon注册为一个全局组件

javascript 复制代码
import SvgIcon from './index.vue';

const svgRequire = require.context('@assets/svgIcons', false, /.svg$/);
svgRequire.keys().forEach((svgIcon) => {
    svgRequire(svgIcon);
});

// 完成全局注册,这里传入的是main.js中创建的app实例
export default (app) => {
    app.component('svg-icon', SvgIcon);
};
2.1. 为啥要使用require.context?
  • require.context 是 Webpack 提供的一个功能,用于在编译时动态加载模块。它的作用是在指定目录中匹配文件,并生成一个上下文模块,从而可以在代码中动态引入这些文件
  • 这里的作用是将svgIcons目录下的文件全部加载到项目中, 如果使用 svg-sprite-loader,这些 SVG 文件会被打包成 SVG Sprite,并通过 <use> 标签引用。如何配置svg-sprite-loader,参考如下

3. svg-sprite-loader插件配置

css 复制代码
{
        test: /\.svg/,
        include: path.resolve(__dirname, '../src/assets/svgIcons'),
        use: {
          loader: 'svg-sprite-loader',
          options: {
            symbolId: 'icon-[name]', // 生成唯一的 symbolId
          }
        }
      }
  • 使用include过滤了目录
  • symbolId名称是svg文件的唯一标识,和上文的SvgIcon.vue组件的传参icon属性一一对应,不然use的href属性在Svg雪碧图中找不到对应的svg标签模块了!!!
  • svg-sprite-loader处理过后的svg文件会被打包成如下类似结果,注意id属性就是我们注入的symbolId
xml 复制代码
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="icon-icon1" viewBox="0 0 24 24">
    <!-- icon1.svg 的内容 -->
  </symbol>
  <symbol id="icon-icon2" viewBox="0 0 24 24">
    <!-- icon2.svg 的内容 -->
  </symbol>
  <symbol id="icon-icon3" viewBox="0 0 24 24">
    <!-- icon3.svg 的内容 -->
  </symbol>
</svg>

总结

完结撒花 ~ 如有不足之处,欢迎指出!日有所积,终有所获!

参考

developer.mozilla.org/zh-CN/docs/...

相关推荐
乌兰麦朵12 分钟前
Vue吹的颅内高潮,全靠选择性失明和 .value 的PUA!
前端·vue.js
Code季风12 分钟前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
蓝倾13 分钟前
如何使用API接口实现淘宝商品上下架监控?
前端·后端·api
舂春儿14 分钟前
如何快速统计项目代码行数
前端·后端
毛茸茸14 分钟前
⚡ 从浏览器到编辑器只需1秒,这个React定位工具改变了我的开发方式
前端
Pedantic15 分钟前
我们什么时候应该使用协议继承?——Swift 协议继承的应用与思
前端·后端
Software攻城狮16 分钟前
vite打包的简单配置
前端
Codebee16 分钟前
如何利用OneCode注解驱动,快速训练一个私有的AI代码助手
前端·后端·面试
流星稍逝17 分钟前
用vue3的写法结合uniapp在微信小程序中实现图片压缩、调整分辨率、做缩略图功能
前端·vue.js
知了一笑20 分钟前
独立开发问题记录-margin塌陷
前端