当前位置: 首页 > news >正文

Vue3中的Icon理方案

在前端项目开发中,SVG(可缩放矢量图形)凭借其无损缩放、体积小、可编辑性强等诸多优势,成为了处理图标(Icon)的热门选择。本文将为大家详细介绍几种在项目中处理 SVG 图作为 Icon 的有效方法。

用组件的方式引入Svg将其作为Icon-vite-svg-loader

vite-svg-loader不仅仅可以通过组件形式导入,还可以通过url、string的形式进行导入。

vite.config.js

import vue from '@vitejs/plugin-vue'
import SvgLoader from 'vite-svg-loader'


export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())

  return {
    base: env.VITE_APP_BASE_URL + '/',
    plugins: [
      vue(), 
      svgLoader()
    ]
})

 结合业务场景为svgLoader做一些额外配置

import vue from '@vitejs/plugin-vue'
import SvgLoader from 'vite-svg-loader'


export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())

  return {
    base: env.VITE_APP_BASE_URL + '/',
    plugins: [
      vue(), 
      svgLoader(
         {
              svgoConfig: {
                plugins: [
                  {
                    name: 'removeAttrs',
                    // 保留这些属性,但不包括id
                    params: { attrs: '(data-name|class|style)' },
                  },
                  {
                    // 使用 cleanupIds 插件但要小心配置以避免误删除或修改ID
                    name: 'cleanupIds',
                    params: {
                      // 或者使用 minify: false 来禁用 minify 功能,以此保留原始 Ids,不追加的话,svgo会修改svg的id,svg的显示会互相影响
                      minify: false,
                    },
                  },
                ],
              },
            }
      )
    ]
})

 将svg图导出

icon
├── assets // 存放图片
│   └── table.svg
└── src // 抛出所有svg图
    └── index.ts

导出方式一: Icon会有代码提示

除了可以按组件的形式导出,还可以按Url的方式导出


// icon->src->index.ts
// 所有svg图都在此处追加
export { default as table } from '../assets/table.svg?component'
<template>
  <div>
   <table></table>
  </div>
</template>

<script setup lang="ts">
import { table } from '@/components/icon'

defineOptions({
  name: 'Icon',
})

</script>

 导出方式二:这种方式导出的话,没有代码提示

const svgModules = import.meta.glob('../assets/*.svg', {
  eager: true,
  query: 'component',
})

// 抛出一个对象,对象中的键名是文件名称,值是`svgModules` 中对应 `path` 的模块
const icons = Object.keys(svgModules).reduce((pre, path) => {
  const file = path.split('/')
  const fileName = file[file.length - 1].split('.')[0]
  pre[fileName] = svgModules[path]
  return pre
}, {} as any)

export default icons
<template>
  <div>
   <table></table>
  </div>
</template>

<script setup lang="ts">
import icons from '@/components/icon'

const { table } = icons

defineOptions({
  name: 'Icon',
})

 使用@iconify/vue插件

npm install --save-dev @iconify/vue

在线方式

<template>
  <Icon icon="carbon:bot" />
</template>

<script setup lang="ts">
import { Icon } from '@iconify/vue'
</script>

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

离线方式

默认Iconify是在线加载的,访问有可能不稳定,很多时候私有化部署不能加载外网数据,因此我们需要离线加载。因为Iconify是在线加载元数据,因此,我们可以改为本地自动引入。

导入整个数据集

整个导入图标集,会导致图标集里的图片全部被打包进assets的js文件中,dist文件会特别大。

npm install @iconify/vue @iconify/json
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { Icon } from '@iconify/vue';
// 引入需要的图标集,这里以 Material Design Icons 为例
import materialDesignIcons from '@iconify/json/json/mdi.json';
import { addCollection } from '@iconify/core';

// 添加图标集到 Iconify
addCollection(materialDesignIcons);

const app = createApp(App);
app.component('Icon', Icon);
app.mount('#app');    

 app.vue

<template>
  <div>
    <!-- 使用 mdi 图标集中的图标 -->
    <Icon icon="mdi:home" />
  </div>
</template>

<script setup>
// 无需额外导入,因为已经在 main.js 中全局注册
</script>    

按需加载方式 - 手动按需加载

npm install @iconify/vue

全部数据
npm add -D @iconify/json


部分数据(以Material Design Icons为例)
npm add -D @iconify-json/mdi

图片按需加载工具
npm add -D unplugin-icons

tsconfig.json 

 "compilerOptions": {
    "types": ["unplugin-icons/types/vue"],
  }

 装Vite的图标自动引入插件

// vite.config.ts

import Icons from 'unplugin-icons/vite'  //图标按需加载工具

export default defineConfig({
  plugins: [
    Icons(), //图标按需加载工具
  ],
})

 

<script setup>
import IconAccessibility from '~icons/carbon/accessibility'
import IconAccountBox from '~icons/mdi/account-box'
</script>

<template>
  <icon-accessibility/>
  <icon-account-box style="font-size: 2em; color: red"/>
</template>

按需加载方式 - 自动按需加载

安装按需加载插件
npm add unplugin-vue-components -D
// vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

//icon按需引入
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite'

export default defineConfig({
    plugins: [
        vue(),
        Components({
            resolvers: [
                 IconsResolver({
                    prefix: 'icon'  // 更改图标前缀
                }),
            ],
        }),
        Icons(),
    ],
})

 在组件中使用

<template>
  <! --使用icon-->
  <icon-mdi-home />
</template>

<script setup>
</script>

参考内容

https://zhuanlan.zhihu.com/p/688842750

https://juejin.cn/post/7087827571861585956#heading-0

使用vite-plugin-svg-icons插件渲染svg类型的Icon

// svg-icon.vue组件
<template>
  <svg
    aria-hidden="true"
    class="svg-icon"
    :style="'width:' + width + ';height:' + height"
  >
    <use :xlink:href="symbolId" :fill="color" />
  </svg>
</template>

<script setup lang="ts">
import { computed } from 'vue';

const props = defineProps({
  prefix: {
    type: String,
    default: 'icon'
  },
  iconClass: {
    type: String,
    required: false
  },
  color: {
    type: String
  },
  width: {
    type: String,
    default: '12px'
  },
  height: {
    type: String,
    default: '12px'
  }
});

const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`);
</script>

<style scoped>
.svg-icon {
  vertical-align: -0.15em;
  overflow: hidden;
  fill: currentColor;
}
</style>
// vite.config.ts
import vue from "@vitejs/plugin-vue";
import path from "path";
import { UserConfig, ConfigEnv, loadEnv } from "vite";
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';


export default ({ mode }: ConfigEnv): UserConfig =>{
  // 获取.env环境配置
  const env = loadEnv(mode, process.cwd());
  return {
    base: env.VITE_APP_BASE+'/',
    plugins: [
      vue(),
      createSvgIconsPlugin({
        // 指定需要缓存的图标文件夹
        iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
        // 指定symbolId格式
        symbolId: 'icon-[dir]-[name]'
      })
    ],
   
    resolve: {
      // Vite路径别名配置
      alias: {
        '@': path.resolve('./src')
      }
    }
  }
};
// main.ts

import { createApp } from 'vue';
import App from './App.vue';
// 引入svg注册脚本
import 'virtual:svg-icons-register';
// 引入svg组件
import SvgIcon from '@/components/svg-icon/index.vue';

const app = createApp(App);

// 注册全局组件
app
  .component('svg-icon', SvgIcon)


export default app;
<template>
  <div class="bottom-bar">
   <!-- icon-class的值与src/assets/icons内的文件名相同 -->
   <svg-icon icon-class="version"></svg-icon>
  </div>
</template>

<script setup lang="ts">
</script>

<style lang="scss" scoped>

</style>

相关文章:

  • OCR第三个方案:PP-OCRv4的初步探索
  • 2015年国家队选拔赛试题改编题
  • 基于卷积神经网络的眼疾识别系统,resnet50,efficentnet(pytorch框架,python代码)
  • 什么是开发者社区(Developer Communities)?
  • OCCT(2)Windows平台编译OCCT
  • 【大模型】微调一个大模型需要多少 GPU 显存?
  • 论文阅读《P​roximal Curriculum for Reinforcement Learning Agents》——提升智能体学习速度的
  • 11 配置Hadoop集群-免密登录
  • OpenBMC:BmcWeb 处理http请求3 字典树查找节点
  • 搜索算法------深度优先搜索
  • 解锁AI潜能:模型上下文协议(MCP)的革新与应用
  • 原生应用与Web应用的融合演进:现代跨平台开发指南
  • 常见集合篇(一):算法复杂度分析,从理论到业务场景的深度解析
  • 2025年江苏公路水运安全员ABC证精选考试题库
  • 【Android Studio】下载安装过程(详细)
  • LangChain4j(2):整合SpringBoot
  • MCP服务:五分钟实现微服务治理革命,无缝整合Nacos/Zookeeper/OpenResty
  • 【QT5 网络编程示例】TCP 通信
  • Spring Boot启动流程
  • 力扣每日一题:2712——使所有字符相等的最小成本
  • 西安网站优化排名案例/重庆seo代理
  • 买一款app要多少钱/seo及网络推广招聘
  • 济南市病疾情最新信息/seo网站整站优化
  • 大良营销网站建设市场/变现流量推广app
  • 美食网站建设方案/google搜索中文入口
  • 做视频网站推广/市场营销计划书模板