如何在Vue.JS中使用图标组件

原文链接:https://gist.github.com/Justineo/fb2ebe773009df80e80d625132350e30

本文对原文进行一次翻译,并从React开发者的角度简单地做了一些解读。

此文不包含字体图标和SVG sprite。仅在此讨论允许用户按需导入的图标系统。

There are three major ways of exposing API of an icon component in Vue.js and each one of them has its own pros & cons:

在Vue.js的生态里,有3种主流的API形态,它们有各自的优缺点:

1.使用单一的组件(如<v-icon>),让乃通过name或者type属性来指定真正的图标。

图标的数据通过一个全局的“池子”来注册。

	// v-icon/flag.js
	import Icon from 'v-icon'
	import { mdiFlag } from '@mdi/js'
	Icon.add('flag', mdiFlag)

然后这样子使用:

	<template>
	 <v-icon name="flag" />
	</template>

	<script>
	import VIcon from 'v-icon'
	import 'v-icon/flag'

	export default {
	 components: {
		VIcon
	 }
	}
	</script>

在我维护的VueAwesome(内置了FontAwesome图标的组件库)中用了这个方案,同时我认为这是当前最符合人机工程学的形式。不过图标的name属性和那些纯副作用的模块的导入之间的关系比较隐式,图标的数据也在全局注册。如果你有多个不同版本的v-icon,就可能出现问题。

FontAwesome官方的Vue.js组件用了一个稍微不同的方案,它们让用户自己主动把图标加到全局的池子中(也可能我不应该把这个方式归类到这个方案中):

	import { library } from '@fortawesome/fontawesome-svg-core'
	import { faUserSecret } from '@fortawesome/free-solid-svg-icons'

	library.add(faUserSecret)

2.用一个单一的维护(如<v-icon),用户通过data或content之类的属性创建真正的图标。

用户主动把图标的数据传递给组件:

	<template>
	 <v-icon :content="mdiFlag" />
	</template>

	<script>
	import VIcon from 'v-icon'
	import { mdiFlag } from '@mdi/js'

	export default {
	 components: {
		VIcon
	 },
	 created() {
		Object.assign(this, {
		 mdiFlag
		})
	 }
	}
	</script>

这是Vuetify支持的方式(Vuetify通过这种方式支持多种图标的使用方式),这种试在人机工程和直观性上有些损失,但没有方案1的缺点。

3.每个组件代表不同的图标(如<icon-flag />、<icon-star />等)。

这个方案里,每个组件通过一个图标工厂创造出来:

	// icon-flag.js
	import { mdiFlag } from '@mdi/js'
	import { createIcon } from 'v-icon'

	export default createIcon('flag', mdiFlag)

并通过这种方式使用:

	<template>
	 <icon-flag />
	</template>

	<script>
	import { IconFlag } from 'v-icon'

	export default {
	 components: {
		VIcon,
		IconFlag
	 }
	}
	</script>

这种方案在React社区里被广泛采用,我在本文的后续部分将展开讨论。

每个组件代表一个图标

我将更深入地说一下这种方案在Vue.js中的使用。

在Vue.js中,模板和脚本是分开的,组件通过components选项注册。不过就像我们知道的,如果一个组件要用很多图标的话,这种方式会挺麻烦。

Vue 2

<template>
 <div>
 <!-- inline -->
 <icon-flag />

 <!-- conditional -->
 <icon-flag v-if="flag" />
 <icon-star v-else />

 <!-- dynamic -->
 <component :is="flag ? IconFlag : IconStar" />
 </div>
</template>

<script>
import { IconFlag, IconStar } from 'foo-icons'

export default {
 components: {
 IconFlag,
 IconStar
 },
 data() {
 return {
  flag: true
 }
 },
 created() {
 Object.assign(this, {
  IconFlag,
  IconStar
 })
 }
}
</script>

可以看到如果想用图标的is绑定,我们必须把components手动暴露到渲染上下文中。我们可以用字符串去替换组件定义来绕过,但对代码检查和类型系统来说就不那么友好。

<template>
 <div>
 <!-- inline -->
 <icon-flag />

 <!-- conditional -->
 <icon-flag v-if="flag" />
 <icon-star v-else />

 <!-- dynamic -->
 <component :is="flag ? 'icon-flag' : 'icon-star'" />
 </div>
</template>

<script>
import { IconFlag, IconStar } from 'foo-icons'

export default {
 components: {
 IconFlag,
 IconStar
 },
 data() {
 return {
  flag: true
 }
 }
}
</script>

Vue 3

<template>
 <!-- inline -->
 <icon-flag />

 <!-- conditional -->
 <icon-flag v-if="flag" />
 <icon-star v-else />

 <!-- dynamic -->
 <component :is="flag ? IconFlag : IconStar" />
</template>

<script>
import { ref } from 'vue'
import { IconFlag, IconStar } from 'foo-icons'

export default {
 components: {
 IconFlag,
 IconStar
 },
 setup() {
 const flag = ref(true)

 return {
  flag,
  IconFlag,
  IconStar
 }
 }
}
</script>

如果用:is绑定,<script>部分会变成这样:

import { ref } from 'vue'
import { IconFlag, IconStar } from 'foo-icons'

export default {
 components: {
 IconFlag,
 IconStar
 },
 setup() {
 const flag = ref(true)

 return {
  flag
 }
 }
}

如果我们采纳<script components>这样的形式的话:

<template>
 <!-- inline -->
 <icon-flag />

 <!-- conditional -->
 <icon-flag v-if="flag" />
 <icon-star v-else />

 <!-- dynamic -->
 <component :is="flag ? 'icon-flag' : 'icon-star'" />
</template>

<script components>
export { IconFlag, IconStar } from 'foo-icons'
</script>

<script>
import { ref } from 'vue'

export default {
 setup() {
 const flag = ref(true)

 return {
  flag
 }
 }
}
</script>

或者用<script setup>提案:

<script setup>
import { ref } from 'vue'

export const flag = ref(true)
</script>

后记

这很篇文章很精练地介绍了在Vue中按需引入图标的方式,与React社区做比较,可以看到两个生态的差异还是存在的。在React社区中,使用第3种方式(每个图标一个组件)非常普遍,如NPM上排名较高的react-icons和知名组件库@ant-design/icons、@material-ui/icons都是这一形态。

这可能是由于React社区中并不倾向将“组件”这一概念特殊化,组件就是普通的函数、普通的类,所以它的复用于其它的函数、类的复用相同,如同lodash会导出很多个工具函数一样,一个图标库会导出很多个图标组件非常合理。

在文中对于使用createIcon工厂函数的使用有一些可以优化的点。正常使用工厂函数会让创建的组件不可被tree shaking,其原因是语法分析会认为createIcon函数本身是有副作用的,因此这个调用不能被安全地删除。可以通过terser的特殊注释来标记:

// icon-flag.js
import { mdiFlag } from '@mdi/js'
import { createIcon } from 'v-icon'

export default /*#__PURE__*/createIcon('flag', mdiFlag)

以上就是如何在Vue.JS中使用图标组件的详细内容,更多关于Vue.JS中使用图标组件的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vue.js 图标选择组件实践详解

    本文介绍了Vue.js 图标选择组件实践详解,分享给大家,具体如下: 背景 最近项目中在做一个自定义菜单需求,其中有一个为菜单设置小图标的功能,就是大家常见的左侧菜单 设置图标不难,方案就是字体图标,可供使用的图标库也有很多,比如阿里巴巴的 Iconfont,以及 Fontaswsome 等,问题在于如何优雅的提供几百个图标供用户选择,而不需要开发去一个一个的写标签,也不需要一个个的去找图标. 字体图标库 Fontawesome 方案 我们使用字体图标的方式,一般是一个 <i class="

  • Vue 解决通过this.$refs来获取DOM或者组件报错问题

    1.关于this.$refs的使用场景 如果ref属性加在普通元素上,那么this.$refs.name则指向该DOM元素 <p ref="p">hello</p> <!-- this.$refs.p 指向该DOM元素 --> 如果ref属性加在组件上,那么this.$refs.name指向该组件实例 <child-component ref="child"></child-component> <!

  • vue+vuex+axios从后台获取数据存入vuex,组件之间共享数据操作

    在vue项目中组件间相互传值或者后台获取的数据需要供多个组件使用的情况很多的话,有必要考虑引入vuex来管理这些凌乱的状态,今天这边博文用来记录这一整个的过程,后台api接口是使用webpack-server模拟的接口,这个前面的文章中有提到,需要的可以去翻阅. 整个的流程是在组件的created中提交dispatch,然后通过action调用一个封装好的axios然后再触发mutation来提交状态改变state中的数据,然后在组件的计算属性中获取state的数据并渲染在页面上 首先新需要在项

  • vue 组件之间事件触发($emit)与event Bus($on)的用法说明

    组件之间事件触发 之前使用组件,并不是很频繁,是水平的问题,目前工作中,公司大佬带着我手写过一个组件,再此很感谢他的指导.目前简单的组件已经有了自己的逻辑思维,正在从低级码农向中级码农蜕变.废话不多说.上图看看组件情况. 新增按钮组件: 操作按钮组合组件: 此时有个需求就是,无论是哪个按钮,如果改变了列表中的数据,列表需要实时更新数据. 此时就需要用到组件间的事件触发. 父子组件之间事件触发可以使用$emit $emit的使用方法如下: 在子组件中,写一个click点击事件.比如: cancel

  • vue 组件简介

    什么是组件? web的组件其实就是页面组成的一部分,好比是电脑中的每一个元件(如硬盘.键盘.鼠标),它是一个具有独立的逻辑和功能或界面,同时又能根据规定的接口规则进行相互融合,变成一个完整的应用. web页面就是由一个个类似这样的部分组成的,比如导航.列表.弹窗.下拉菜单等.页面只不过是这些组件的容器,组件自由组合形成功能完整的界面,当不需要某个组件,或者想要替换某个组件时,可以随时进行替换和删除,而不影响整个应用的运行. 前端组件化的核心思路就是将一个巨大复杂的东西才分成粒度合理的小东西. 使

  • vue mounted组件的使用

    1.钩子函数 钩子函数是Windows消息处理机制的一部分,通过设置"钩子",应用程序可以在系统级对所有消息.事件进行过滤,访问在正常情况下无法访问的消息.钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统.(百度百科) 2.相对于前端来讲 对于前端来说,钩子函数就是指再所有函数执行前,我先执行了的函数,即 钩住 我感兴趣的函数,只要它执行,我就先执行. 3.vue中的mounted 在这发起后端请求,拿回数据,配合路由钩子做一些事情 类型:Function 详细: e

  • Vue组件跨层级获取组件操作

    this.$parent 访问父实例 this.$children 当前实例的直接子组件.(不保证顺序,不是响应式) this.$parent.$parent.$refs.xxx 跨级访问父组件 this.$children.$children.$refs.xxx 跨级访问子组件 这种递归的方式 代码繁琐 性能低效 ref 只能获取当前组件上下文组件 无法跨层级 ref 是字符串 被用来给元素或子组件注册引用信息. 引用信息将会注册在父组件的 $refs 对象上. 如果在普通的 DOM 元素上使

  • vue组件 $children,$refs,$parent的使用详解

    本文介绍了vue组件 $children,$refs,$parent的使用,分享给大家,也自己留个笔记 如果项目很大,组件很多,怎么样才能准确的.快速的寻找到我们想要的组件了?? 1)$refs 首先你的给子组件做标记.demo :<firstchild ref="one"></firstchild> 然后在父组件中,通过this.$refs.one就可以访问了这个自组件了,包括访问自组件的data里面的数据,调用它的函数 2)$children 他返回的是一个

  • Vue-Router来实现组件间跳转的三种方法

    通过VueRouter来实现组件之间的跳转,供大家参考,具体内容如下 提供了3种方式实现跳转: ①直接修改地址栏中的路由地址 <!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="js/vue.js"></script> <!-- 引入文件 --> &

  • vue如何引用其他组件(css和js)

    1.vuejs组件之间的调用components 注意:报错Do not use built-in or reserved HTML elements as component id: 修改组件的名字,例如不能使用address为组件名字 组件名字不要使用内置的或保留HTML元素为组件id, App.vue是一个入口,vue必须注册才能使用 2.vue引入外部的css,放在和引入vue的位置一样 ./代表当前项目,../代表上一级项目 import '../static/style/reset.

  • 在 Vue 中编写 SVG 图标组件的方法

    在考虑了将矢量图标从图标字体迁移到内联 SVG 的 原因 之后,我在 Vue.js 中找到了一个用 SVG 替换图标字体的解决方案,同时仍能保持使用图标字体的灵活性和易用性--能够使用 CSS 轻松改变图标的大小.颜色以及其它属性. 一种流行的方法是使用 v-html 指令和 npm 模块 html-loader 来将 SVG 导入到我们的 Vue 模板中,并在 Vue 的生命周期函数 mounted() 中修改渲染的 <svg> 元素.CSS 样式可以直接应用到 <svg> 元素

  • vue内置组件component--通过is属性动态渲染组件操作

    我就废话不多说了,大家看代码吧~ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script src="https://cdn.bootcss.com

  • vue之父子组件间通信实例讲解(props、$ref、$emit)

    组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.那么组件间如何通信,也就成为了vue中重点知识了.这篇文章将会通过props.$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信. 在说如何实现通信之前,我们先来建两个组件father.vue和child.vue作为示例的基础. //父组件 <template> <div> <h1>我是父组件!</h1> <child>

随机推荐