likes
comments
collection
share

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

作者站长头像
站长
· 阅读数 55

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

1. 前言

我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、Ant Design 等。

这些组件库虽然方便,但是也有一些缺点,比如内置的图标太少。

例如我们开发医疗、财务、工程等一些前端项目,内置的图标不能满足我们的需求。所以我们需要引入外部的图标。

我们常常在 Vue 项目中引入 SVG 图标。

2. 效果展示

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

3. SVG 简介

SVG 指可伸缩矢量图形 (Scalable Vector Graphics)。

SVG 是使用 XML 来描述二维图形和绘图程序的语言。

说白了 SVG 就跟 jpg、png 一样,都是图形。只不过这玩意是用 xml 语言设计开发的矢量图。

因为是矢量图,所以不管放大还是缩小,都不会失真

我们分别看3个相同名称不同尺寸的 SVG 图标:

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

我们用 vscode 打开一个 SVG 图标,发现它由很多标签组成:

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

如果想深入了解 SVG ,大家可以去以下网站学习

https://www.runoob.com/svg/svg-tutorial.html
https://developer.mozilla.org/zh-CN/docs/Web/SVG

4. 下载 SVG 图标

网上可以下载 SVG 图标的网站有很多,这里我强烈推荐阿里巴巴的 iconfont ,因为它有海量免费的图标供大家学习使用。

官网:

https://www.iconfont.cn/

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

1.选择图标,点击下载按钮

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

2.选择颜色和尺寸之后,点击下载 SVG 格式

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

3.添加到购物车,批量下载

我们也可以将要下载的图标添加到购物车,然后批量下载

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

下载之后,接下来我们需要 在 vue 项目中引入这些图标。

5. Vue3 引入 SVG 图标

前提:使用 Vite 脚手架开发 Vue3 项目。

如果你还不知道如何使用 Vite 开发 Vue3 项目,请看如下文章:

在 Vite 中使用 Vue3 引入 SVG 图标,我们需要借助以下插件:

vite-plugin-svg-icons

vite-plugin-svg-icons 是一个 Vite 插件,它的主要功能是将 SVG 图标转换为 Vue 组件,并自动导入到项目中。

5.1 安装插件

npm i vite-plugin-svg-icons -D

安装之后运行程序如果报这个错误,需要再安装 fast-glob 插件

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

npm i fast-glob -D

5.2 main.js 中注册插件

import 'virtual:svg-icons-register'

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

5.3 配置 vite.config.js

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import { resolve } from "path";
const pathSrc = resolve(__dirname, "src");
export default defineConfig({
  plugins: [
    vue(),
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [resolve(pathSrc, "assets/icons")],
      // 指定symbolId格式
      symbolId: "icon-[dir]-[name]",
    }),],
  resolve: {
    // 设置别名
    alias: {
      '@': resolve(__dirname, resolve(__dirname, "./src"))
    }
  },
});

其中最关键的是指定 svg 图标的存放位置:

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

5.4 封装展示 SVG 图标的 icon 组件

1.:xlink:href 用来绑定图标的名称,名称前要加前缀 icon

2.fill 属性用来设置图标的颜色

<template>
  <svg aria-hidden="true" :fill="color" :style="'width:' + size + ';height:' + size">
    <use :xlink:href="symbolId" />
  </svg>
</template>

<script setup>
import { computed } from "vue";
const props = defineProps({
  // icon 名字
  name: {
    type: String,
    default: "",
  },
  // 填充颜色
  color: {
    type: String,
    default: "black",
  },
  // 大小
  size: {
    type: String,
    default: "1em",
  },
});
const symbolId = computed(() => `#icon-${props.name}`);
</script>

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

5.5 使用组件

<template>
  <div class="content">
    <SvgIcon name="client" size="10rem" />
    <SvgIcon name="client" size="10rem" color="red" />
    <SvgIcon name="client" size="10rem" color="green" />
  </div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon/index.vue";
</script>
<style lang="scss" scoped></style>

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、 Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

6. 批量导入 SVG 图标

1.import.meta.glob 用来动态导入所有 svg 图标

2.获取所有图标的名称

<template>
  <div class="content">
    <SvgIcon
      v-for="(iconName, index) in allIconNames"
      :key="index"
      :name="iconName"
      size="5rem"
    />
  </div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon/index.vue";
import { onMounted, toRef, ref } from "vue";
const allIconNames = ref([]); // 所有的图标名称集合
onMounted(() => {
  loadAllIcons();
});
// 获取所有 icon
const loadAllIcons = () => {
  const icons = import.meta.glob("@/assets/icons/*.svg");
  for (const icon in icons) {
    // 获取 icon 名称
    const iconName = icon.split("/src/assets/icons/")[1].split(".")[0];
    allIconNames.value.push(iconName);
  }
};
</script>
<style lang="scss" scoped></style>

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

7. 开发 SVG 搜索组件

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

这里我们使用 element-plus 作为前端组件库。

我们主要用到 el-input、el-popover、el-scrollbar、el-tooltip 组件。

在 components 文件夹下新建 SelectIcon 组件

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

在开发这个组件之前,我们先想一下流程:

1.首先封装 el-input,prepend 需要用 SvgIcon 展示选中图标,v-model 需要绑定该图标的名称。

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

2.点击 el-input, 弹出 el-popover,也就是需要给 el-popover 绑定 visible。

3.el-popover上面需要展示搜索框,下面需要展示所有的图标。

// 加载 icon
onMounted(() => {
  loadAllIcons();
});
// 获取所有图标
const loadAllIcons = () => {
  const icons = import.meta.glob("@/assets/icons/*.svg");
  for (const icon in icons) {
    const iconName = icon.split("/src/assets/icons/")[1].split(".")[0];
    allIconNames.value.push(iconName);
  }
  filterIconNames.value = allIconNames.value;
};

4.图标太多需要滚动,所以需要 el-scrollbar 组件进行包裹。

Vue3如何引入SVG图标?一篇文章快速学会!我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、

5.筛选图标需要根据所有 SVG 的名称是否包含 filterName

// 筛选 icon
const filterIcon = () => {
  if (filterValue.value) {
    filterIconNames.value = allIconNames.value.filter((iconName) =>
      iconName.includes(filterValue.value)
    );
  } else {
    filterIconNames.value = allIconNames.value;
  }
};

6.点击图标需要更新父组件绑定的值

update:modelValue 是 v-model 指令的默认事件,用于在组件内部通知父组件更新绑定的值。

const handleSelect = (iconName) => {
  emit("update:modelValue", iconName);
  visible.value = false;
};

<el-form-item
  label="图标:"
  prop="icon"
>
  <icon-select ref="IconSelectRef" v-model="sysMenu.icon" />
</el-form-item>

7.1 SelectIcon 组件完整代码

<template>
  <div class="content">
    <el-input
      style="width: 100%"
      v-model="inputIconValue"
      readonly
      placeholder="点击选择图标"
      @click="visible = !visible"
    >
      <template #prepend>
        <SvgIcon :size="20" :name="inputIconValue" />
      </template>
    </el-input>
    <el-popover
      shadow="none"
      :visible="visible"
      placement="bottom-end"
      trigger="click"
      width="400"
    >
      <template #reference>
        <div @click="visible = !visible">
          <i-ep-caret-top v-show="visible" />
          <i-ep-caret-bottom v-show="!visible" />
        </div>
      </template>
      <!-- 下拉选择弹窗 -->
      <div>
        <el-row :gutter="10">
          <el-col :span="18">
            <el-input
              v-model="filterValue"
              placeholder="输入图标名称"
              clearable
              @input="filterIcon"
            />
          </el-col>
          <el-col :span="6">
            <el-button @click="closeIcon()">关闭</el-button>
          </el-col>
        </el-row>
        <el-divider border-style="dashed" />

        <el-scrollbar height="300px">
          <div class="icon-list">
            <el-tooltip
              v-for="(iconName, index) in filterIconNames"
              :key="index"
              :content="iconName"
              placement="bottom"
              effect="light"
            >
              <div class="icon-item" @click="handleSelect(iconName)">
                <SvgIcon :name="iconName" />
              </div>
            </el-tooltip>
          </div>
        </el-scrollbar>
      </div>
    </el-popover>
  </div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon/index.vue";
import { onMounted, toRef, ref } from "vue";
const visible = ref(false); // 弹窗显示状态
const allIconNames = ref([]); // 所有的图标名称集合
const filterIconNames = ref([]); // 筛选之后名称集合
const filterValue = ref(""); // 筛选的值
// 修改父组件关联的值
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: {
    type: String,
    require: false,
    default: "",
  },
});
const inputIconValue = toRef(props, "modelValue");
// 加载 icon
onMounted(() => {
  loadAllIcons();
});
// 获取所有图标
const loadAllIcons = () => {
  const icons = import.meta.glob("@/assets/icons/*.svg");
  for (const icon in icons) {
    const iconName = icon.split("/src/assets/icons/")[1].split(".")[0];
    allIconNames.value.push(iconName);
  }
  filterIconNames.value = allIconNames.value;
};
// 筛选 icon
const filterIcon = () => {
  if (filterValue.value) {
    filterIconNames.value = allIconNames.value.filter((iconName) =>
      iconName.includes(filterValue.value)
    );
  } else {
    filterIconNames.value = allIconNames.value;
  }
};
// 选择 icon
const handleSelect = (iconName) => {
  emit("update:modelValue", iconName);
  visible.value = false;
};

// 关闭组件
const closeIcon = () => {
  visible.value = false;
  filterValue.value = "";
  filterIconNames.value = allIconNames.value;
};
</script>
<style lang="scss" scoped>
.el-divider--horizontal {
  margin: 10px auto !important;
}
.icon-list {
  display: flex;
  flex-wrap: wrap;
  .icon-item {
    display: flex;
    justify-content: center;
    padding: 5px 0px;
    margin: 5px;
    width: 10%;
    cursor: pointer;
    border: 1px solid #ccc;

    &:hover {
      color: var(--el-color-primary);
      border-color: var(--el-color-primary);
      transition: all 0.2s;
      transform: scaleX(1.1);
    }
  }
}
</style>


8. 项目完整代码

拿到代码之后记得先 npm install 安装相关插件,再 npm run dev 运行。

链接: https://pan.baidu.com/s/10hnexE2mPcoKJbexylPK7g?pwd=1234 
提取码: 1234 
转载自:https://juejin.cn/post/7408797826019704883
评论
请登录