vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3引入SVG图标

Vue3引入SVG图标的流程步骤

作者:知否技术

我们在开发 Vue 项目的时候会使用一些前端组件库,例如 Element、Ant Design 等,这些组件库虽然方便,但是也有一些缺点,比如内置的图标太少,例如我们开发医疗、财务、工程等一些前端项目,内置的图标不能满足我们的需求,所以我们常常在Vue项目中引入SVG图标

1. 前言

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

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

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

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

2. 效果展示

3. SVG 简介

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

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

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

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

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

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

如果想深入了解 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/

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

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

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

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

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

5. Vue3 引入 SVG 图标

前提:使用 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 插件

npm i fast-glob -D

5.2 main.js 中注册插件

import 'virtual:svg-icons-register'

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 图标的存放位置:

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" rel="external nofollow"  />
  </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>

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>

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>

7. 开发 SVG 搜索组件

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

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

在 components 文件夹下新建 SelectIcon 组件

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

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

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 组件进行包裹。

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>


以上就是Vue3引入SVG图标的流程步骤的详细内容,更多关于Vue3引入SVG图标的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文