vue3 - 按需导入使用Element Plus图标、iconify图标、本地SVG/PNG图标

GitHub Demo 地址

在线预览

vue项目使用的图标一般有本地的png、svg图标,Element图标,还有就是通过自动导入使用三方库iconify的图标

一、iconify插件

Iconify for Vue 官方文档

Iconify内的 element-plus图标

Iconify 是一个开源的图标集和图标管理工具。它提供了一个庞大的图标库,包含数千个常用图标,涵盖了各种主题和风格,如 Material Design、Font Awesome、Feather 等。这些图标可以以矢量格式(SVG)使用,适用于各种项目,如网站、移动应用、桌面应用等。

安装

npm install --save-dev @iconify/vue

使用

用法

import { Icon } from '@iconify/vue'

    <!-- https://github.com/iconify/iconify/tree/main/components/vue -->
    <Icon icon="ep:add-location" height="24" />
    <Icon icon="mdi-light:home" width="16" height="16" />
    <Icon icon="mdi-light:home" height="24" />
    <Icon icon="mdi-light:home" height="2em" />
    <Icon icon="mdi-light:home" height="auto" />
    <Icon icon="eva:alert-triangle-fill" color="orange" />
    <Icon icon="eva:alert-triangle-fill" color="#f00" />

    <div>
      <!-- 水平翻转图标: -->
      <Icon icon="eva:alert-triangle-fill" :h-flip="true" />
      <Icon icon="eva:alert-triangle-fill" :horizontal-flip="true" />
      <Icon icon="eva:alert-triangle-fill" flip="horizontal" />
      <!-- 垂直翻转图标 -->
      <Icon icon="eva:alert-triangle-fill" :v-flip="true" />
      <Icon icon="eva:alert-triangle-fill" :vertical-flip="true" />
      <Icon icon="eva:alert-triangle-fill" flip="vertical" />
      <!-- 水平和垂直翻转图标(与180度旋转相同): -->
      <Icon icon="eva:alert-triangle-fill" :h-flip="true" :v-flip="true" />
      <Icon icon="eva:alert-triangle-fill" :horizontal-flip="true" :vertical-flip="true" />
      <Icon icon="eva:alert-triangle-fill" flip="horizontal,vertical" />
      <!-- 90度旋转的例子: -->
      <Icon icon="eva:alert-triangle-fill" :rotate="1" />
      <!-- <Icon icon="eva:alert-triangle-fill" rotate="90deg" />
      <Icon icon="eva:alert-triangle-fill" rotate="25%" /> -->
    </div>

效果图

二、通过自动导入使用iconify

安装Element Plus

element plus 按需导入 官方文档
element plus 使用icon图标 官方文档

通过element plus使用icon图标,可以通过以下两种方式(本文通过方式2)
1、可以通过命令npm install @element-plus/icons-vue单独安装icons-vue组件,然后使用
2、也可以通过使用 unplugin-iconsunplugin-auto-importiconify 中自动导入任何图标集。 您可以参考此模板

element plus使用icon图标一般是通过组件的方式使用的,如 <Search />,或者自动导入配置后<i-ep-edit />

npm install element-plus

安装自动导入插件

安装两个按需导入的插件,避免在多个页面重复引入 API 或 组件
unplugin-auto-import 按需自动导入API,如:ref,reactive,watch,computed 等API
unplugin-vue-components 按需自动导入组件,如:Element Plus 等三方库和指定目录下的自定义组件

npm install -D unplugin-auto-import unplugin-vue-components

安装自动导入 Icon 插件

使用 unplugin-iconsunplugin-auto-import可以从 iconify 中自动导入图标

npm i -D unplugin-icons

vite.config.ts 配置自动导入,新建 /src/types目录用于存放自动导入函数auto-imports.d.ts和组件的TS类型声明文件components.d.ts

import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

plugins: [
     AutoImport({
      // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
      imports: ['vue', '@vueuse/core'],
      // imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'],
      eslintrc: {
        enabled: false, // 是否自动生成 eslint 规则,建议生成之后设置 false,手动维护
        filepath: './.eslintrc-auto-import.json', // 指定自动导入函数 eslint 规则的文件路径
        globalsPropValue: true
      },
      resolvers: [
        // 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)
        ElementPlusResolver(),
        IconsResolver({})
      ],
      vueTemplate: true,
      // 配置文件生成位置(false:关闭自动生成)
      dts: false
      // dts: 'src/types/auto-imports.d.ts' // 指定自动导入函数TS类型声明文件路径
    }),

    Components({
      resolvers: [
        // 自动导入 Element Plus 组件
        ElementPlusResolver(),
        // 自动导入图标组件
        IconsResolver({
          // @iconify-json/ep 是 Element Plus 的图标库
          enabledCollections: ['ep']
        })
      ],
      // 指定自定义组件位置(默认:src/components)
      dirs: ['src/**/components'],
      // 配置文件位置(false:关闭自动生成)
      dts: false
      // dts: "src/types/components.d.ts",
    }),

    Icons({
      // 自动安装图标库
      autoInstall: true
    }),
]

.eslintrc.cjs 添加自动导入函数 eslint 规则

"extends": [
    "./.eslintrc-auto-import.json"
]

tsconfig.json 添加自动导入TS类型声明文件

{
  "include": ["src/**/*.d.ts"]
}

运行项目 npm run dev 查看效果

通过iconify使用Element Plus图标

<template>
    <h1>iconify 图标:</h1>
    <div>
      <icon1 />
      <!-- <icon2 /> -->
      <icon3 />
    </div>
    
    <div>
      <i-ep-edit />
      <el-icon :size="19.2" color="#409eff">
        <i-ep-edit />
      </el-icon>
    </div>
</template>

<script setup lang="ts">
// element-plus图标
// https://icon-sets.iconify.design/ep/
import icon1 from '~icons/ep/help-filled'
// import { HelpFilled } from '@element-plus/icons-vue'

// 其他的
// https://icon-sets.iconify.design/
// import icon2 from '~icons/mdi/home-clock'
// 动态图标
// https://icon-sets.iconify.design/line-md/
// https://icon-sets.iconify.design/svg-spinners/
import icon3 from '~icons/line-md/home'
</script>

效果图

通过 UnoCSS,Element Plus 像 Element UI 一样使用 Icon

Vue3!Element Plus 如何像 Element UI 一样使用 Icon?

UnoCSS官网

UnoCSS 是一个具有高性能且极具灵活性的即时原子化 CSS 引擎 ,用于构建响应式网页和应用程序界面。它提供了一套简洁、易于使用的样式类,帮助开发者快速搭建漂亮且功能强大的界面。

npm add -D unocss

vite.config.ts 配置

import UnoCSS from 'unocss/vite'
import { presetIcons } from 'unocss'

export default {
  plugins: [
  
    // 配置UnoCSS,使其可以直接使用标签 <i-ep-edit /> | <el-button icon="i-ep-edit" > edit </el-button>
    // UnoCSS({})
    UnoCSS({
      presets: [
        presetIcons({
          scale: 1.2,
          warn: true
        })
      ],
      // 以下配置是为了可以直接使用标签 <i-ep-edit /> | <el-button icon="i-ep-edit" > edit </el-button>
      variants: [
        {
          match: (s) => {
            if (s.startsWith('i-')) {
              return {
                matcher: s,
                selector: (s) => {
                  return s.startsWith('.') ? `${s.slice(1)},${s}` : s
                }
              }
            }
          }
        }
      ]
    })


  ],
}

main.ts 引入 uno.css

import 'uno.css'

示例

    <h2>el-button+图标:</h2>
    <el-button type="primary">
      <el-icon> <i-ep-edit /> </el-icon> 新增
    </el-button>
    <el-button type="primary" icon="i-ep-edit"> 新增 </el-button>

效果图

三、SVG本地图标

通过 vite-plugin-svg-icons 插件使用 Iconfont 第三方图标库实现本地SVG图标展示
vite-plugin-svg-icons 官方文档

npm install -D fast-glob
npm install -D vite-plugin-svg-icons

先指定一个存放svg的路径,如:src/assets/iconssrc/assets/error

vite.config.ts 中配置插件

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'

const resolve = (dir: string) => path.resolve(process.cwd(), dir)

plugins: [
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [resolve('src/assets/icons'), resolve('src/assets/error')],
      // iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
      // 指定symbolId格式
      symbolId: 'icon-[dir]-[name]'
    }),
]

src/main.ts 内引入注册脚本

import 'virtual:svg-icons-register'

封装一个SVG 组件以供项目使用
在src/components/创建SvgIcon文件夹,创建index.vue

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

<script setup lang="ts">
const props = defineProps({
  prefix: {
    type: String,
    default: 'icon'
  },
  iconClass: {
    type: String,
    required: false,
    default: ''
  },
  color: {
    type: String,
    default: ''
  },
  size: {
    type: String,
    default: '1em'
  }
})

const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`)
</script>

<style scoped>
.svg-icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em; /* 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果 */
  outline: none;
  fill: currentcolor; /* 定义元素的颜色,currentColor是一个变量,这个变量的值就表示当前元素的color值,如果当前元素未设置color值,则从父元素继承 */
}
</style>
<template>
     <h1>img SVG本地图片:</h1>
    <svg-icon icon-class="homepage" />
    <svg-icon icon-class="user" color="red" />
</template>

<script setup lang="ts">
import SvgIcon from '@/components/SvgIcon/index.vue'
</script>

效果图

四、本地PNG图标

vue3中使用本地图标和vue2还是有点区别

vue2使用的require,如:<img :src="require('@/assets/test.png')" />

vue3和vite中使用require会报错(require is not definedrequire is not defined),因为requirewebpack提供的方法,在vite中不适用。在vite中,由于使用了 ES modules 的方式来加载模块,因此不能使用 require,而是使用import

以下是vue3中使用本地PNG图标的方式(调试和线上图标都显示)

<template>
    <h1>img 本地PNG图片:</h1>
    <img src="../../../assets/images/static/icon.png" />
    <img :src="imgPath2" />
    <img :src="imgPath3" />
    <img :src="imgPath4" />
    <img :src="imgPath5" />

    <h2>img 本地图片动态导入:</h2>
    <img :src="getImgPath2('icon2.png')" />
    <img :src="getImgPath3('icon3.png')" />
</template>

<script setup lang="ts">
import imgPath2 from '@/assets/images/static/icon2.png'
const imgPath3 = getImgPath('icon3.png')
const imgPath4 = new URL(`../../../assets/images/static/icon4.png`, import.meta.url).href
const imgPath5 = new URL(`@/assets/images/static/icon5.png`, import.meta.url).href

const getImgPath2 = (name: string): any => {
  return new URL(`/src/assets/images/static/${name}`, import.meta.url).href
}

const getImgPath3 = (name: string): any => {
  return new URL(`../../../assets/images/static/${name}`, import.meta.url).href
}

</script>

!!!!注意:

  TODO: 下面这样写加载失败,也不可以用@/assets/xxx
  return new URL('/src/assets/images/static/' + name, import.meta.url).href

效果图

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容