Vue项目中SVG图标

文章目录

  • [一、SVG 图标管理的优势](#一、SVG 图标管理的优势)
  • [二、SVG 图标存储结构](#二、SVG 图标存储结构)
  • [三、SVG 图标的加载与注册机制](#三、SVG 图标的加载与注册机制)
    • [1. 自动加载核心代码](#1. 自动加载核心代码)
    • [2. 工作原理](#2. 工作原理)
  • [四、svg-sprite-loader 配置](#四、svg-sprite-loader 配置)
    • [1. 安装依赖](#1. 安装依赖)
    • [2. Vue CLI 配置](#2. Vue CLI 配置)
    • [3. 传统 Webpack 配置](#3. 传统 Webpack 配置)
  • [五、SVG 图标组件实现](#五、SVG 图标组件实现)
  • [六、SVG 图标的完整处理流程](#六、SVG 图标的完整处理流程)
    • [1. 构建阶段](#1. 构建阶段)
    • [2. 运行阶段](#2. 运行阶段)
  • [七、SVG 优化配置](#七、SVG 优化配置)
    • [1. SVGO 配置文件](#1. SVGO 配置文件)
    • [2. 优化脚本](#2. 优化脚本)
    • [3. 执行优化](#3. 执行优化)
  • [八、在项目中使用 SVG 图标](#八、在项目中使用 SVG 图标)
    • [1. 基本使用](#1. 基本使用)
    • [2. 颜色控制](#2. 颜色控制)
    • [3. 大小控制](#3. 大小控制)

一、SVG 图标管理的优势

  • 矢量图形:无限缩放不失真
  • 文件体积小:通常比位图小,加载快
  • 可编辑性强:可通过 CSS 和 JavaScript 修改
  • 支持动画:可实现丰富的交互动画效果
  • 响应式:自适应不同屏幕尺寸
  • 颜色可控:支持通过 CSS 统一控制颜色

二、SVG 图标存储结构

复制代码
src/
├── icons/
│   ├── index.js       # 图标注册文件
│   ├── svgo.yml       # SVGO 优化配置
│   └── svg/           # SVG 文件存储目录
│       ├── user.svg
│       ├── password.svg
│       └── ...
  • 存储位置src/icons/svg 目录
  • 文件格式 :标准 .svg 文件
  • 组织方式 :扁平化管理,直接放入 svg 目录

三、SVG 图标的加载与注册机制

1. 自动加载核心代码

文件src/icons/index.js

javascript 复制代码
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component

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

// 自动加载所有 SVG 文件
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

2. 工作原理

  1. 创建文件上下文

    • require.context('./svg', false, /\.svg$/) 创建一个文件加载上下文
    • 扫描 src/icons/svg 目录下的所有 .svg 文件
  2. 批量加载

    • req.keys() 返回所有匹配文件的相对路径数组
    • map(requireContext) 对每个路径执行加载操作
  3. 全局注册

    • Vue.component('svg-icon', SvgIcon) 全局注册组件
    • 全项目可直接使用 <svg-icon> 标签

四、svg-sprite-loader 配置

1. 安装依赖

bash 复制代码
# 安装 svg-sprite-loader
npm install svg-sprite-loader --save-dev

# 安装 SVGO(可选,用于优化 SVG)
npm install svgo --save-dev

2. Vue CLI 配置

文件vue.config.js

javascript 复制代码
const path = require('path')

function resolve(dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  chainWebpack(config) {
    // 排除默认 SVG 处理
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()
    
    // 配置 svg-sprite-loader
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()
  }
}

3. 传统 Webpack 配置

javascript 复制代码
const path = require('path')

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/,
        include: path.resolve(__dirname, 'src/icons'),
        use: [
          {
            loader: 'svg-sprite-loader',
            options: {
              symbolId: 'icon-[name]'
            }
          }
        ]
      }
    ]
  }
}

五、SVG 图标组件实现

文件src/components/SvgIcon/index.vue

html 复制代码
<template>
  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
import { isExternal } from '@/utils/validate'

export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    isExternal() {
      return isExternal(this.iconClass)
    },
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
    styleExternalIcon() {
      return {
        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
      }
    }
  }
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}

.svg-external-icon {
  background-color: currentColor;
  mask-size: cover!important;
  display: inline-block;
}
</style>

六、SVG 图标的完整处理流程

1. 构建阶段

  1. 文件准备 :将 SVG 文件放入 src/icons/svg 目录
  2. 依赖安装npm install 安装所有依赖
  3. SVG 优化npm run svgo 优化 SVG 文件
  4. 项目构建npm run buildnpm run dev
  5. Webpack 处理
    • svg-sprite-loader 将 SVG 文件转换为 <symbol> 元素
    • 生成唯一的 symbolId(如 icon-user
    • 合并所有 <symbol> 元素到一个 <svg> 元素
    • 将生成的 <svg> 元素注入到 HTML 页面

2. 运行阶段

  1. 应用启动 :加载 src/main.js,引入 ./icons
  2. 组件注册 :全局注册 svg-icon 组件
  3. 图标使用 :在模板中使用 <svg-icon icon-class="图标名">
  4. 浏览器渲染
    • 解析 <svg-icon> 组件
    • 生成对应的 <use> 元素
    • 通过 xlink:href 查找并渲染对应的 <symbol>
    • 应用 CSS 样式(如颜色继承)

七、SVG 优化配置

1. SVGO 配置文件

文件src/icons/svgo.yml

yaml 复制代码
plugins:
- removeAttrs:
    attrs:
      - 'fill'  # 移除填充颜色属性
      - 'fill-rule'  # 移除填充规则属性

2. 优化脚本

文件package.json

json 复制代码
"scripts": {
  "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
}

3. 执行优化

bash 复制代码
npm run svgo

优化效果

  • 移除硬编码的 fill 属性,使图标可继承父元素颜色
  • 移除不必要的属性,减小 SVG 文件体积
  • 确保所有图标风格一致

八、在项目中使用 SVG 图标

1. 基本使用

html 复制代码
<template>
  <div>
    <!-- 基本使用 -->
    <svg-icon icon-class="user" />
    
    <!-- 带自定义类名 -->
    <svg-icon icon-class="password" class="custom-class" />
    
    <!-- 绑定事件 -->
    <svg-icon icon-class="search" @click="handleSearch" />
  </div>
</template>

2. 颜色控制

html 复制代码
<template>
  <div>
    <!-- 默认颜色 -->
    <svg-icon icon-class="user" />
    
    <!-- 自定义颜色 -->
    <svg-icon icon-class="user" style="color: red;" />
    
    <!-- 主题色 -->
    <svg-icon icon-class="user" class="theme-color" />
  </div>
</template>

<style scoped>
.theme-color {
  color: var(--primary-color);
}
</style>

3. 大小控制

html 复制代码
<template>
  <div>
    <!-- 默认大小 -->
    <svg-icon icon-class="user" />
    
    <!-- 自定义大小 -->
    <svg-icon icon-class="user" style="font-size: 24px;" />
    
    <!-- 不同尺寸 -->
    <svg-icon icon-class="user" class="icon-large" />
    <svg-icon icon-class="user" class="icon-small" />
  </div>
</template>

<style scoped>
.icon-large {
  font-size: 32px;
}
.icon-small {
  font-size: 16px;
}
</style>
相关推荐
SJLoveIT2 小时前
【安全研发】CSRF (跨站请求伪造) 深度复盘与防御体系
前端·安全·csrf
pas1362 小时前
34-mini-vue 更新element的children-双端对比diff算法
javascript·vue.js·算法
小二·2 小时前
Python Web 开发进阶实战:数字孪生平台 —— 在 Flask + Vue 中构建实时物理世界镜像
前端·vue.js·python
CHU7290352 小时前
安心陪伴,便捷就医:陪诊代办小程序的温暖设计
前端·小程序·php
ashcn20012 小时前
websocket测试通信
前端·javascript·websocket
weixin_404679312 小时前
edge alt tab怎么关
前端·edge
CHU7290352 小时前
线上扭蛋机拆盒小程序前端功能版块解析
前端·小程序·php
卿着飞翔3 小时前
Vue使用yarn进行管理
前端·javascript·vue.js
夏天想3 小时前
vue通过iframe引入一个外链地址,怎么保证每次切换回这个已经打开的tab页的时候iframe不会重新加载
前端·javascript·vue.js