element-plus & unplugin-icons实现任意icon svg自动导入

5,292 阅读3分钟

本文为自学总结, 谨慎食用, 如有错漏还请指正

前言: element-plus推荐自动导入的组件引入方式

image.png 但icon系列并未列明自动导入使用的方案

image.png 以下为参考诸多网上热心大佬的方案总结的极简版任意icon, 通过svg, 实现自动导入的方法 (主打不用自己封装组件.. 配置好 下载下来开箱即用)

配置用例使用vue3+vite 所有配置参考本文末尾

前言2: 本文主要参考 @isboyjc 这位热心大佬的这篇文章: Vue3!ElementPlus!更加优雅的使用Icon

更详尽的使用方案欢迎移步阅读

需要的插件

前置需要的自动导入插件:

导入组件

npm i unplugin-vue-components -D

导入函数

npm i -D unplugin-auto-import

unplugin-icons

这是自动导入icon 核心依赖的插件

内置 iconify 自动导入

 npm i -D unplugin-icons

template使用示例

根据配置, 图标组件名格式需要遵循preffix-collection-name

preffix: 前缀,此处配置为icon

collection: 集合名, 可以是iconify里面的集合名, 或者自定义的本地icon集合名

name:icon的标识, 自定义的就是svg文件名

// element-plus(需要通过iconify引入)
  <el-icon :size="20" color="#ff44aa">
    <icon-ep-edit />
  </el-icon>
// 自定义 可以来自任意来源 比如阿里的 iconfont 或者自制
  <el-icon :size="20" color="#ff44aa">
    <icon-my-pie />
  </el-icon>
  

自动导入element-plus(以及其他iconify集合)

自动导入element-plus icon的方法: 从iconify里面安装他的集合 而不是从官方安装.. 详见这篇文章

iconify的使用: colleciton-name:icon-name image.png

自动导入自定义icon

配置vite.config.js

//plugins.Components

    Components({
      resolvers: [
        // Auto register icon components
        // 自动注册图标组件
        IconsResolver({
          prefix: 'icon',
          // this is optional, default enabling all the collections supported by Iconify
          enabledCollections: ['ep'], // 这是element-plus在iconify的集合名,  这行不配置也可以, 会识别iconify有的集合名 只要用了就自动下载 自动导入
          customCollections: ['my'] // **** 这里配置组件内需要使用的自定义集合名
        }),
        // Auto register Element Plus components
        // 自动导入 Element Plus 组件
        ElementPlusResolver(),
      ],

      dts: path.resolve(pathSrc, 'components.d.ts'),
    }),
//plugins.Icons

    Icons({
      autoInstall: true,
      customCollections: {
        'my': FileSystemIconLoader('src/assets/icons'), //配置自定义集合的路径, 更详细的配置可参考插件仓库
      }
    }),

自动导入iconfont(阿里图标)

  1. 如何从阿里图标批量下载svg文件

找了一个chrome插件, 可自行斟酌使用 下载地址

  1. 如何去除svg 里的fill

直接下载iconfont的svg 会有fill属性, 导致用element-plus改图标样式不成功 可以直接在iconfont的项目里批量去色 详情参考这篇文章

完整的vite.config.js配置参考

import { fileURLToPath, URL } from 'node:url'

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

//icon相关
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
//autoimport相关
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'

//element-plus自动导入解析
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

const path = require('path')
const pathSrc = path.resolve(__dirname, 'src')

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),

    AutoImport({
      // Auto import functions from Vue, e.g. ref, reactive, toRef...
      // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
      imports: ['vue'],

      // Auto import functions from Element Plus, e.g. ElMessage, ElMessageBox... (with style)
      // 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)
      resolvers: [
        ElementPlusResolver(),

        // Auto import icon components
        // 自动导入图标组件
        IconsResolver({
          prefix: 'Icon',
        }),
      ],

      dts: path.resolve(pathSrc, 'auto-imports.d.ts'),
    }),

    Components({
      resolvers: [
        // Auto register icon components
        // 自动注册图标组件
        IconsResolver({
          prefix: 'icon',
          // this is optional, default enabling all the collections supported by Iconify
          enabledCollections: ['ep', 'pixelarticons'], // iconify的集合名称
          customCollections: ['my']
        }),
        // Auto register Element Plus components
        // 自动导入 Element Plus 组件
        ElementPlusResolver(),
      ],

      dts: path.resolve(pathSrc, 'components.d.ts'),
    }),

    Icons({
      autoInstall: true,
      customCollections: {
        'my': FileSystemIconLoader('src/assets/icons'),
      }
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

补充: 自动导入+ 动态导入

根据antfu解答, unplugin-component 设计是为静态使用的情况设计的, issue里面有其他大佬总结的 动态导入方式, 可以参考 传送门

  AutoImport({
      imports: ["vue"],
      resolvers: [
        IconsResolver({
          componentPrefix: "icon",
          enabledCollections: ["carbon", "mdi"], // 似乎需要显式声明要用到的集合
        }),
      ],
      dts: "src/auto-imports.d.ts",
    }),

然后就能无需手动导入, 在script里面直接引用icon组件

<script setup>
const items = [
{
  name: 'Alarm',
  icon: IconMdiAlarm, //*
},
{
  name: 'Account',
  icon: IconMdiAccount, //*
}
]
</script>

<template>
  <div v-for="i of items">
      <el-icon>
        <component :is="i.icon"/>
       </el-icon>
  </div>
</template>