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


Posted in Javascript onAugust 04, 2020

原文链接: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中使用图标组件的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
基于JavaScript 声明全局变量的三种方式详解
May 07 Javascript
javascript:文字不间断向左移动的实例代码
Aug 08 Javascript
Javascript delete 引用类型对象
Nov 01 Javascript
简介AngularJS的HTML DOM支持情况
Jun 17 Javascript
基于jQuery实现简单的折叠菜单效果
Nov 23 Javascript
JavaScript如何实现对数字保留两位小数一位自动补零
Dec 18 Javascript
由浅入深剖析Angular表单验证
Jul 14 Javascript
JQuery Dialog对话框 不能通过Esc关闭的原因分析及解决办法
Jan 18 Javascript
ajax 提交数据到后台jsp页面及页面跳转问题
Jan 19 Javascript
vue 2.1.3 实时显示当前时间,每秒更新的方法
Sep 16 Javascript
Vue+axios封装请求实现前后端分离
Oct 23 Javascript
js实现弹幕墙效果
Dec 10 Javascript
如何构建 vue-ssr 项目的方法步骤
Aug 04 #Javascript
vue-quill-editor的使用及个性化定制操作
Aug 04 #Javascript
vue 添加和编辑用同一个表单,el-form表单提交后清空表单数据操作
Aug 03 #Javascript
浅谈vue中get请求解决传输数据是数组格式的问题
Aug 03 #Javascript
VUE使用axios调用后台API接口的方法
Aug 03 #Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
Aug 03 #Javascript
js数组中去除重复值的几种方法
Aug 03 #Javascript
You might like
优化使用mysql存储session的php代码
2008/01/10 PHP
PHP isset()与empty()的使用区别详解
2010/08/29 PHP
php 数组的一个悲剧?
2011/05/11 PHP
php实现递归抓取网页类实例
2015/04/03 PHP
PHP针对字符串开头和结尾的判断方法
2016/07/11 PHP
PHP获取对象属性的三种方法实例分析
2019/01/03 PHP
jquery 页面全选框实践代码
2010/04/02 Javascript
JS异常处理的一个想法(sofish)
2013/03/14 Javascript
一个js过滤空格的小函数
2014/10/10 Javascript
JS实现跟随鼠标立体翻转图片的方法
2015/05/04 Javascript
jquery获取复选框的值的简单实例
2016/05/26 Javascript
JS实现动态表格的添加,修改,删除功能(推荐)
2016/06/15 Javascript
JS创建对象的写法示例
2016/11/04 Javascript
禁用backspace网页回退功能的实现代码
2016/11/15 Javascript
移动端web滚动分页的实现方法
2017/05/05 Javascript
js中getter和setter用法实例分析
2018/08/14 Javascript
vue+SSM实现验证码功能
2018/12/07 Javascript
javascript中this的用法实践分析
2019/07/29 Javascript
VSCode搭建Vue项目的方法
2020/04/30 Javascript
Ant Design Vue table中列超长显示...并加提示语的实例
2020/10/31 Javascript
[50:21]Liquid vs Winstrike 2018国际邀请赛小组赛BO2 第二场
2018/08/19 DOTA
Python中一些自然语言工具的使用的入门教程
2015/04/13 Python
从Python的源码浅要剖析Python的内存管理
2015/04/16 Python
Python简单连接MongoDB数据库的方法
2016/03/15 Python
Python实现简单的HttpServer服务器示例
2017/09/25 Python
python编程培训 python培训靠谱吗
2018/01/17 Python
python给指定csv表格中的联系人群发邮件(带附件的邮件)
2019/12/31 Python
python中spy++的使用超详细教程
2021/01/29 Python
Notino罗马尼亚网站:购买香水和化妆品
2019/07/20 全球购物
经济与贸易专业应届生求职信
2013/11/19 职场文书
教师的实习自我鉴定
2013/12/17 职场文书
会计学生自我鉴定
2014/02/06 职场文书
职业生涯规划书范文
2014/03/10 职场文书
学生安全承诺书
2014/05/22 职场文书
党员违纪检讨书怎么写
2014/11/01 职场文书
美德少年主要事迹材料
2015/11/04 职场文书