在 Vue 中使用 SVG 图标

SVG 图标因其矢量特性、高清晰度及样式易定制等优势,已成为现代 Web 开发的首选。在 Vue 项目中优雅地引入 SVG 图标可通过多种方案实现,下面将详细解析四种主流方案。

方案一:直接通过 <img> 引入(基础版)

适用于简单场景,但无法动态修改样式。

vue 复制代码
<template>
  <img src="@/assets/icons/home.svg" alt="首页" width="24" height="24">
</template>

优点 :简单快捷

缺点:无法通过 CSS 修改颜色/样式;多次使用产生额外 HTTP 请求。


方案二:使用 vue-svg-loader(转为 Vue 组件)

将 SVG 转换为可复用的 Vue 组件。

步骤:

  1. 安装 loader
bash 复制代码
npm install vue-svg-loader svgo-loader --save-dev
# 或
yarn add vue-svg-loader svgo-loader -D
  1. 配置 vue.config.js
js 复制代码
module.exports = {
  chainWebpack: (config) => {
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons')) // 排除原文件夹处理规则
      .end();

    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons')) // 指定 SVG 目录
      .end()
      .use('vue-svg-loader')
      .loader('vue-svg-loader')
      .options({ 
        svgo: { plugins: [{ removeViewBox: false }] } // 保留 viewBox 属性
      });
  }
};
  1. 组件中使用
vue 复制代码
<template>
  <HomeIcon class="icon" />
</template>

<script>
import HomeIcon from '@/icons/home.svg';

export default {
  components: { HomeIcon }
}
</script>

<style scoped>
.icon {
  fill: #42b983; /* 直接修改填充色 */
  transition: fill 0.3s;
}
.icon:hover {
  fill: #ff7e67;
}
</style>

优点 :完全支持 Vue 响应式样式

缺点:每个图标需单独引入


方案三:使用 svg-sprite-loader(雪碧图方案)

合并所有 SVG 为单个雪碧图,通过 <use> 引用。

步骤:

  1. 安装依赖
bash 复制代码
npm install svg-sprite-loader --save-dev
  1. 配置 vue.config.js
js 复制代码
module.exports = {
  chainWebpack: (config) => {
    // 默认 SVG 规则排除 icons 目录
    config.module
      .rule('svg')
      .exclude.add(path.resolve(__dirname, 'src/icons'))
      .end();

    // 添加 icons 目录专属规则
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(path.resolve(__dirname, 'src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({ symbolId: 'icon-[name]' }); // symbolId 命名规则
  }
};
  1. 创建全局组件 SvgIcon.vue
vue 复制代码
<template>
  <svg :class="className" aria-hidden="true">
    <use :xlink:href="`#icon-${name}`" />
  </svg>
</template>

<script>
export default {
  props: {
    name: { type: String, required: true },  // SVG 文件名
    className: String                       // 自定义样式类
  }
};
</script>
  1. 在入口文件(如 main.js)自动导入所有 SVG
js 复制代码
const req = require.context('./icons', false, /\.svg$/);
req.keys().map(req);
  1. 组件中使用
vue 复制代码
<template>
  <SvgIcon name="home" class="custom-class" />
</template>

<script>
import SvgIcon from '@/components/SvgIcon.vue';

export default {
  components: { SvgIcon }
}
</script>

方案四:使用 unplugin-icons(自动化最优解)

基于按需导入的现代解决方案,无需手动管理 SVG 文件。

步骤:

  1. 安装依赖
bash 复制代码
npm install -D unplugin-icons @iconify/json
# 或
yarn add -D unplugin-icons @iconify/json
  1. 配置 vite.config.js / vue.config.js
js 复制代码
// Vite 配置 (vite.config.js)
import Icons from 'unplugin-icons/vite';

export default {
  plugins: [
    Vue(), 
    Icons({ compiler: 'vue3' }) // 'vue2' for Vue 2
  ]
};
  1. 在组件中直接使用(按需导入)
vue 复制代码
<template>
  <div>
    <!-- 直接使用 Iconify 图标名 -->
    <Icon icon="mdi:home" width="24" />
    
    <!-- 使用本地 SVG -->
    <Icon icon="custom:home" :path="customSvgPath" />
  </div>
</template>

<script setup>
import { Icon } from '@iconify/vue';

// 本地 SVG 示例
const customSvgPath = `
  <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/> 
`;
</script>
  1. 动态修改样式
vue 复制代码
<template>
  <Icon icon="mdi:email" class="icon-style" />
</template>

<style>
.icon-style {
  color: #3498db;  /* 修改颜色 */
  font-size: 2em;  /* 调整大小 */
  transition: all 0.3s;
}
.icon-style:hover {
  color: #e74c3c;
  transform: rotate(15deg);
}
</style>

核心优势

  • 按需自动加载(无多余代码)
  • 支持 10,000+ 开源 Iconify 图标集
  • 本地/远程 SVG 统一管理
  • 极致开发体验(HMR 热更新)

各方案对比表

方案 按需加载 样式控制 维护成本 适用场景
<img> 标签 ★☆☆☆☆ 简单静态场景
vue-svg-loader 部分 ★★★☆☆ 少量自定义图标
svg-sprite-loader ★★★★☆ 中大型项目
unplugin-icons ★★★★★ 现代化项目首选方案

最佳实践建议

  1. 小型项目 → 使用 vue-svg-loader 快速起步
  2. 中大型项目 → 采用 svg-sprite-loaderunplugin-icons
  3. 图标库依赖 → 优先选择 unplugin-icons + Iconify 生态
  4. 性能优化
    • 使用 SVGO 压缩 SVG(在线工具
    • 通过 ?raw 避免 URL 编码问题(Vite)
    • 动态加载非核心图标(import() + 骨架屏)
相关推荐
伍哥的传说5 分钟前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_4244091912 分钟前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding13 分钟前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜14 分钟前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui
SevgiliD15 分钟前
el-button传入icon用法可能会出现的问题
前端·javascript·vue.js
我在北京coding16 分钟前
Element-Plus-全局自动引入图标组件,无需每次import
前端·javascript·vue.js
鱼 空18 分钟前
解决el-table右下角被挡住部分
javascript·vue.js·elementui
柚子81628 分钟前
scroll-marker轮播组件不再难
前端·css
你的人类朋友1 小时前
🫏光速入门cURL
前端·后端·程序员
01传说2 小时前
vue3 配置安装 pnpm 报错 已解决
java·前端·vue.js·前端框架·npm·node.js