Vue3+Element Plus使用svg加载iconfont的解决方案

简介: Element UI作为一款优秀的开源组件库,想必很多人都使用过,在Vue3中,我们需要使用Element Plus。Element Plus有很多好用的组件,详细用法可直接去查看官方文档:[Element Plus](https://element-plus.org/zh-CN/)。本文主要介绍如何在Vue3+Element Plus的项目中,使用自己封装的svg图标。

Element UI作为一款优秀的开源组件库,想必很多人都使用过,在Vue3中,我们需要使用Element Plus。Element Plus有很多好用的组件,详细用法可直接去查看官方文档:Element Plus。本文主要介绍如何在Vue3+Element Plus的项目中,使用自己封装的svg图标。

安装依赖

由于我们是Vue3项目,可以使用vite来快速创建一个Vu3项目:

npm install -g yarn
yarn create vite my-vue-app --template vue // 这里我们使用vue模板,默认是Javascript语法,如果需要ts语法则需要指定模板为vue-ts
cd my-vue-app
yarn
yarn dev

创建好项目后,我们再来引入Element Plus,安装并引入的过程如下:

安装

yarn add element-plus

完整引入

// main.js
...
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)

引入后,我们就可以在Vue3项目中使用了:

<template>
    <el-button>按钮</el-button>
</template>

Element Plus使用Icon会比Element UI稍微麻烦点。首先我们需要安装Icon的依赖:

yarn add @element-plus/icons-vue

我们在main.js中注册所有的图标,当然也可以按需引入图标:

// main.js
// 全局引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
...
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

el-icon的使用:

<template>
    <el-icon>
        <Edit />
    </el-icon>
</template>
<script setup>
// import {Edit} from '@element-plus/icons-vue' // 按需引入,如果已经全局引入了就不需要按需引入
</script>

Element Plus的el-icon使用的是svg,这与Element UI使用的类名有很大的不同,也就是说我们无法直接在el-icon中使用iconfont的图标。虽然Element Plus的图标已经能满足大部分场景的需求,但是一些特殊场景只能从iconfont或者自定义的图标上获取。

那么有没有办法将iconfont封装成svg,并给el-icon调用呢?

将iconfont封装成svg

可缩放矢量图形(Scalable Vector Graphics),简称SVG,是一种基于XML的,可用于描述二维的矢量图形。SVG可以优雅而简洁的渲染不同大小的图形,并且可以被无限缩放并且保持不失真或者降低质量,这一特性比JPEGPNG等好用太多。SVG的内容相当多,感兴趣的可以去MDN上查看文档:SVG。我们这里只是简单实用SVG来封装iconfont。

首先我们新建一个SvgIcon.vue的文件,

<template>
  <svg :class="classList" aria-hidden="true">
    <use :xlink:href="iconName" :fill="color" />
  </svg>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
  className: {
    type: String,
    default: ''
  },
  iconClass: {
    type: String,
    required: true
  },
  color: {
    type: String,
    default: '#409eff'
  },
  size: {
    type: String,
    default: '20px'
  }
})
const classList = computed(() => {
  return ['icon', props.className || '']
})
const iconName = computed(() => {
  return `#${props.iconClass}`
})
</script>
<style scoped>
.icon {
  /* v-bind是Vue3才支持的功能,可以将CSS的值与js的值绑定 */
  width: v-bind('props.size');
  height: v-bind('props.size');
  position: relative;
  vertical-align: -2px;
  fill: currentColor;
}
</style>

这样就将iconfont封装成了svg来调用了,这里我们重点说几个属性:

  • aria-hidden:默认为false,设置为true表示会把整个元素包括子元素从可访问树(AOM)上移除,但是在DOM树上还是存在的
  • xlink:hrefuse元素的属性
  • v-bind:Vue3的特性,可用于关联CSS和js
  • fill:如果在动画接收还需要保持动画的值,可用于设置颜色

如何使用

使用已经封装好的SvgIcon.vue比较简单,就和正常的组件一样使用即可。例如:

<template>
    <SvgIcon :icon-class="icon-pointer"></SvgIcon>
</template>
<script setup>
import SvgIcon from './SvgIcon.vue'
</sript>

如果不想在局部注册组件,也可以注册为全局组件:

// main.js
import SvgIcon from '@/SvgIcon.vue'
...
app.component('SvgIcon', SvgIcon);

作为SVG组件,我们也可以直接使用在el-icon中,这样就可以添加任意iconfontel-icon中了:

<template>
    <el-icon>
        <SvgIcon :icon-class="icon-pointer"></SvgIcon>
    </el-icon>
</template>

按理说到这里,本篇教程就应该结束了。但是,在使用的过程中,按照正常的方式设置的hover样式不生效,笔者尝试了几种方案,最终放弃hover,采用监听鼠标事件的方式解决。

设置”hover“样式

SVG不同于class样式,其无法直接通过修改hover样式来设置鼠标悬浮在图标上面时颜色改变,这个时候我们就需要换一种思路了。我们在SvgIcon.vue中传入了color,并且通过fillcolor作用到SVG上,因此我们可以在父组件中修改color的值来实现"hover"效果。

<template>
    <div @mouseenter="() => handleMouseenter" @mouseleave="() => handleMouseleave">
        <SvgIcon :icon-class="icon-pointer" :color="color"></SvgIcon>
    </div>
</template>
<script setup>
import {ref} from 'vue'
const color = ref('red')
const handleMouseenter = () => {
    color.value = 'blue'
}
const handleMouseleave = () => {
    color.value = 'red'
}
</sript>

上面的例子中适用于单个SvgIcon,如果是多个的话,就需要进一步改造了:

<template>
    <div v-for="(item, index) in list" @mouseenter="($event) => handleMouseenter($event, index)" @mouseleave="($event) => handleMouseleave($event, index)">
        <SvgIcon :icon-class="icon-pointer" :color="hoverIconIndex == index ? 'blue' : 'red'"></SvgIcon>
    </div>
</template>
<script setup>
import {ref} from 'vue'
const list = ref([
    {name: '张三'}
])
const color = ref('red')
const hoverIconIndex = ref(-1)
const handleMouseenter = (event, index) => {
    hoverIconIndex.value = index;
}
const handleMouseleave = (event, index) => {
    hoverIconIndex.value = -1;
}
</sript>

对比来看,其实也不复杂。

为什么图标颜色无法修改?

可能有点朋友按照上述的步骤操作后,发现并不能修改图标颜色,如果不是代码有误,那应该就是导入的iconfont有问题。一般我们会直接在iconfont官网下载图标:

image-20220620202526056.png

将下载好的压缩包解压后,只复制iconfont.js到项目中即可:

// main.js
...
import '@/assets/iconfont/iconfont.js';

我们来看一下iconfont.jsicon-close1icon-close的源码:

image-20220620202903141.png

可以发现,这两个图标最大的差别就是一个有fill,另一个没有,而这就是问题的关键。如果某一个图标的fill不为空,那么作为svg引用时将无法修改填充色

举个例子:

<template>
    <div>
        <SvgIcon :color="'red'" :icon-class="'icon-close'"></SvgIcon>
         <SvgIcon :color="'red'" :icon-class="'icon-close1'"></SvgIcon>
    </div>
</template>

运行结果:

image-20220620204721822.png

遇到这个问题应该怎么解决呢,一种方式就是手动删除所有Icon的fill属性,另一个就是在iconfont上面使用批量去色。

image-20220620203320950.png

批量去色后,我们再次下载图标,并解压后替换掉原来的iconfont.js,再去源码看看就会发现所有图标的fill都没有了,而且也可以修改颜色。

总结

本文详细介绍了如何在Element Plus中使用iconfont,简单的说就是要将其封装成SVG,并且支持动态修改颜色。虽然操作上不难,但是容易踩一些坑,你学会了吗?

相关文章
|
20天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
109 1
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
163 64
|
2月前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
142 60
|
26天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
98 3
|
2月前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
86 17
|
2月前
|
JavaScript 前端开发 API
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
101 17
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
57 8
|
2月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
52 1
|
2月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
58 1
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。