封装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/...

相关推荐
范哥来了14 分钟前
python web开发flask库安装与使用
前端·python·flask
顾林海32 分钟前
Flutter Dart 泛型详解
android·前端·flutter
百慕大三角36 分钟前
如何用AI工具设计出令人惊艳的页面(附截图)
前端·trae·ai 编程
唐某人丶40 分钟前
如何优化 React 组件?
前端·react.js·前端框架
树上有只程序猿41 分钟前
Vue3组合式API从原理到实战终极指南
前端
code_Bo1 小时前
vue2使用el-cascader在table中下拉框不跟随滚动问题
前端·vue.js·element
王小菲1 小时前
JavaScript 装箱机制与解构赋值深度解析
前端·javascript·面试
用户49430538293801 小时前
基于GIS数据的即时建筑模型编辑软件
前端·算法·gis
Shawn5901 小时前
如何使用useCallback优化React性能?
前端·react.js
Suckerbin1 小时前
PHP前置知识-HTML学习
前端·学习·html