封装SvgIcon组件

举报
林太白 发表于 2025/01/28 11:06:52 2025/01/28
【摘要】 封装SvgIcon组件

封装SvgIcon组件

1、认识SvgIcon组件作用

首先我们认识一下svg并且知道Svg格式图片的好处,这里可以去看一下之前我写的关于svg部分的文章。

为什么要将svg其封装成一个单独的组件

SvgIcon组件在Vue中用于专门展示SVG图标,可以充分利用SVG的优点,使得图标的显示和交互都能得到更好的支持。

  1. 可缩放性:SvgIcon组件可以利用SVG的特性,使得图标可以在不失真的情况下进行缩放。这对于需要根据用户需求动态调整大小或者需要在不同分辨率下都能清晰显示的图标来说非常有用。
  2. 可编辑性:由于SVG图标是由XML代码定义的,因此可以方便地进行修改和编辑。这在需要定制图标或者图标需要经常变动的情况下非常方便。
  3. 支持复杂交互:SVG图标可以支持鼠标事件(如点击、悬停等),这使得可以在图标上实现一些复杂的交互功能。

2、(项目采用)借vite-plugin-svg-icons -D 封装

这里我的项目采用的是这个方式

我们借助插件实现SvgIcon组件的封装,具体步骤如下:

把我们的svg组件都放到这个下面

src => assets => svg

(1)安装插件:

yarn add -D vite-plugin-svg-icons


yarn add -D vite-plugin-svg-icons

安装成功以后可以看到我们的依赖项

"vite-plugin-svg-icons": "^2.0.1",

(2)配置vite.config.js(vite.config.ts)配置文件,导入,并将其插件配置到plugins数组当中

这里代表我们将svg的所有组件全部封装进入src/assets/svg 这个下面

**vite.config.ts**中配置插件

注意这里的iconDirs 背后的地址就是你svg文件夹的那个地址:


import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

export default defineConfig({
    base: '/',
    plugins: [
        createSvgIconsPlugin({
            iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
            symbolId: 'icon-[dir]-[name]',
        }),
        vue(),
        // svgBuilder('./src/assets/svg/'),// 这里已经将src/assets/svg/下的svg全部导入,无需再单独导入
        //视图分析工具
        visualizer({
            open: true, //在默认用户代理中打开生成的文件
            gzipSize: true, // 收集 gzip 大小并将其显示
            brotliSize: true, // 收集 brotli 大小并将其显示
            filename: "repotrs.html", // 分析图生成的文件名
        }),
    ],
    resolve: {
        // 解决公共路径问题
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    },
    
})

(3)main.ts入口文件导入 (大坑)

配置main.js(main.ts),在其中注册svg图标

import 'virtual:svg-icons-register'

报错:

安装fast-glob依赖

yarn add fast-glob -D

☞ src下面新建立一个components文件夹,下面建立一个 SvgIcon

<template>
  <!--svg外层容器,需要配置子元素use使用-->
  <svg :style="{width, height}">
    <!--xlink:href引用的svg图标,#icon-图标名-->
    <use :xlink:href="symbolId" :fill="fill" />
  </svg>
</template>

<script setup>
import {computed,defineProps} from "vue"
const props = defineProps({
  prefix: {
    type: String,
    default: 'icon'
  },
  name: {
    type: String,
    required: true
  },
  width: {
    type: String,
    default: "16px"
  },
  height: {
    type: String,
    default: "16px"
  },
  fill: {
    type: String,
    default: '#333'
  }
})
// svg icon引入的格式
const symbolId = computed(() => {
  return `#${props.prefix}-${props.name}`
})
</script>

(4)页面使用

这里我们直接就已经可以使用了

<SvgIcon name="collapsetrue"/>
<SvgIcon name="collapsefalse"/>

Icon就可以正常显示了

(5)全局使用

// main.ts之中引入
import SvgIcon from '@/components/SvgIcon/index.vue'
app.component('SvgIcon', SvgIcon) //icon组件
<SvgIcon name="collapsetrue"/>

完成!

3、 借助 svg-sprite-loader 封装

(1)安装

yarn add svg-sprite-loader -D

(2)SvgIcon.vue内容如下

<script setup lang="ts">
import { computed } from 'vue-demi'
const props = defineProps(['name'])
const iconName = computed(() => `#icon-${props.name}`)
</script>

<template>
  <svg class="svg-icon" aria-hidden="true">
    <use :xlink:href='iconName'></use>
  </svg>
</template>

<style lang="scss" scoped>
.svg-icon {
  vertical-align: middle;
  fill: currentColor;
  overflow: hidden;
}
</style>

(3)src下面新建文件夹plugins

在plugins文件夹创建svgBuilder.js插件

import { readFileSync, readdirSync } from 'fs'

let idPerfix = ''
const svgTitle = /<svg([^>+].*?)>/
const clearHeightWidth = /(width|height)="([^>+].*?)"/g

const hasViewBox = /(viewBox="[^>+].*?")/g

const clearReturn = /(\r)|(\n)/g

function findSvgFile(dir) {
  const svgRes = []
  const dirents = readdirSync(dir, {
    withFileTypes: true,
  })
  for (const dirent of dirents) {
    if (dirent.isDirectory()) {
      svgRes.push(...findSvgFile(dir + dirent.name + '/'))
    } else {
      const svg = readFileSync(dir + dirent.name)
        .toString()
        .replace(clearReturn, '')
        .replace(svgTitle, ($1, $2) => {
          // console.log(++i)
          // console.log(dirent.name)
          let width = 0
          let height = 0
          let content = $2.replace(clearHeightWidth, (s1, s2, s3) => {
            if (s2 === 'width') {
              width = s3
            } else if (s2 === 'height') {
              height = s3
            }
            return ''
          })
          if (!hasViewBox.test($2)) {
            content += `viewBox="0 0 ${width} ${height}"`
          }
          return `<symbol id="${idPerfix}-${dirent.name.replace(
            '.svg',
            ''
          )}" ${content}>`
        })
        .replace('</svg>', '</symbol>')
      svgRes.push(svg)
    }
  }
  return svgRes
}

export const svgBuilder = (path, perfix = 'icon') => {
  if (path === '') return
  idPerfix = perfix
  const res = findSvgFile(path)
  // console.log(res.length)
  // const res = []
  return {
    name: 'svg-transform',
    transformIndexHtml(html) {
      return html.replace(
        '<body>',
        `
          <body>
            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
              ${res.join('')}
            </svg>
        `
      )
    },
  }
}

(4)更改vite.config.js配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import { visualizer } from 'rollup-plugin-visualizer'; //视图分析工具
import { svgBuilder } from '@/src/plugins/svgBuilder'; 
export default defineConfig({
    base: '/',
    plugins: [
        vue(),
        svgBuilder('./src/assets/svg/'),// 这里已经将src/assets/svg/下的svg全部导入,无需再单独导入
        //视图分析工具
        visualizer({
            open: true, //在默认用户代理中打开生成的文件
            gzipSize: true, // 收集 gzip 大小并将其显示
            brotliSize: true, // 收集 brotli 大小并将其显示
            filename: "repotrs.html", // 分析图生成的文件名
        }),
    ],
    resolve: {
        // 解决公共路径问题
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    },
    
})

(5)使用


yarn add @element-plus/icons-vue

### 注册所有图标
从 `@element-plus/icons-vue` 中导入所有图标并进行全局注册

// main.ts
// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。