如何在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 相关文章推荐
JQUERY1.6 使用方法四 检测浏览器
Nov 23 Javascript
ASP.NET jQuery 实例2 (表单中使用回车在TextBox之间向下移动)
Jan 13 Javascript
一个级联菜单代码学习及removeClass与addClass的应用
Jan 24 Javascript
js中window.open()的所有参数详细解析
Jan 09 Javascript
javascript的alert box在java中如何显示多行
May 18 Javascript
js+HTML5基于过滤器从摄像头中捕获视频的方法
Jun 16 Javascript
浅析Bootstrip的select控件绑定数据的问题
May 10 Javascript
浅析JavaScript动画模拟拖拽原理
Dec 09 Javascript
js正则表达式惰性匹配和贪婪匹配用法分析
Dec 26 Javascript
JavaScript实现省市联动过程中bug的解决方法
Dec 04 Javascript
详解ES6中的代理模式——Proxy
Jan 08 Javascript
js实现div色块碰撞
Jan 16 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
PHP错误Warning:mysql_query()解决方法
2015/10/24 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
2016/09/21 PHP
PHP中in_array的隐式转换的解决方法
2018/03/06 PHP
JavaScript触发器详解
2007/03/10 Javascript
无语,javascript居然支持中文(unicode)编程!
2007/04/12 Javascript
jquery $.trim()方法使用介绍
2014/05/21 Javascript
jQuery解析json格式数据简单实例
2016/01/22 Javascript
超全面的vue.js使用总结
2017/02/12 Javascript
Map.vue基于百度地图组件重构笔记分享
2017/04/17 Javascript
基于JavaScript实现数码时钟效果
2020/03/30 Javascript
JavaScript中arguments和this对象用法分析
2018/08/08 Javascript
Vue中使用create-keyframe-animation与动画钩子完成复杂动画
2019/04/09 Javascript
JS学习笔记之数组去重实现方法小结
2019/05/29 Javascript
javascript实现图片轮播代码
2019/07/09 Javascript
Node.js HTTP服务器中的文件、图片上传的方法
2019/09/23 Javascript
javaScript 实现重复输出给定的字符串的常用方法小结
2020/02/20 Javascript
JS严格模式原理与用法实例分析
2020/04/27 Javascript
JS将指定的某个字符全部转换为其他字符实例代码
2020/10/13 Javascript
[01:33]完美世界DOTA2联赛PWL S3 集锦第二期
2020/12/21 DOTA
Python入门_浅谈数据结构的4种基本类型
2017/05/16 Python
Python中类的初始化特殊方法
2017/12/01 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
2018/04/18 Python
python 多维切片之冒号和三个点的用法介绍
2018/04/19 Python
Python获取基金网站网页内容、使用BeautifulSoup库分析html操作示例
2019/06/04 Python
Python+OpenCV+图片旋转并用原底色填充新四角的例子
2019/12/12 Python
Python中return函数返回值实例用法
2020/11/19 Python
string = null 和string = ''的区别
2013/04/28 面试题
市场专员岗位职责
2014/02/14 职场文书
六个一活动实施方案
2014/03/21 职场文书
大学班级文化建设方案
2014/05/06 职场文书
不遵守课堂纪律的检讨书
2014/09/24 职场文书
2014年民主评议党员个人总结
2014/09/24 职场文书
财务整改报告范文
2014/11/05 职场文书
丽江古城导游词
2015/02/03 职场文书
村党组织公开承诺书
2015/04/30 职场文书
java项目构建Gradle的使用教程
2022/03/24 Java/Android