如何在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 相关文章推荐
js中将多个语句写成一个语句的两种方法小结
Dec 08 Javascript
jquery nth-child()选择器的简单应用
Jul 10 Javascript
用JavaScript对JSON进行模式匹配(Part 1-设计)
Jul 17 Javascript
浅谈JS之tagNaem和nodeName
Sep 13 Javascript
详解javascript事件绑定使用方法
Oct 20 Javascript
JSON中key动态设置及JSON.parse和JSON.stringify()的区别
Dec 29 Javascript
jquery mobile移动端幻灯片滑动切换效果
Apr 15 Javascript
微信小程序中的swiper组件详解
Apr 14 Javascript
用React实现一个完整的TodoList的示例代码
Oct 30 Javascript
解决vue 引入子组件报错的问题
Sep 06 Javascript
vue 本地服务不能被外部IP访问的完美解决方法
Oct 29 Javascript
Vue 实现从文件中获取文本信息的方法详解
Oct 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中header和session_start前不能有输出原因分析
2013/01/11 PHP
基于PHP CURL用法的深入分析
2013/06/09 PHP
ThinkPHP入库出现两次反斜线转义及数据库类转义的解决方法
2014/11/04 PHP
php中实现记住密码下次自动登录的例子
2014/11/06 PHP
Yii开启片段缓存的方法
2016/03/28 PHP
PHP从零开始打造自己的MVC框架之入口文件实现方法详解
2019/06/03 PHP
Jquery ajax传递复杂参数给WebService的实现代码
2011/08/08 Javascript
解决jquery实现的radio重新选中的问题
2015/07/03 Javascript
Vue.js使用v-show和v-if的注意事项
2016/12/13 Javascript
js实现表格筛选功能
2017/01/18 Javascript
深入对Vue.js $watch方法的理解
2017/03/20 Javascript
基于jQuery封装的分页组件
2017/06/26 jQuery
vue-resource 拦截器(interceptor)的使用详解
2017/07/04 Javascript
详谈JS中数组的迭代方法和归并方法
2017/08/11 Javascript
JS中的多态实例详解
2017/10/15 Javascript
Angularjs Ng_repeat中实现复选框选中并显示不同的样式方法
2018/09/12 Javascript
微信小程序获取当前位置和城市名
2019/11/13 Javascript
vue.js页面加载执行created,mounted的先后顺序说明
2020/11/07 Javascript
在阿里云服务器上配置CentOS+Nginx+Python+Flask环境
2016/06/18 Python
Python实现定时精度可调节的定时器
2018/04/15 Python
python3 爬取图片的实例代码
2018/11/06 Python
bluepy 一款python封装的BLE利器简单介绍
2019/06/25 Python
python全局变量引用与修改过程解析
2020/01/07 Python
导致python中import错误的原因是什么
2020/07/01 Python
解析浏览器的一些“滚动”行为鉴赏
2019/09/16 HTML / CSS
美国最便宜的旅游网站:CheapTickets
2017/07/09 全球购物
Expedia印度:您的一站式在线旅游网站
2017/08/24 全球购物
意大利体育用品和运动服网上商店:Maxi Sport
2019/09/14 全球购物
数字漫画:comiXology
2020/06/13 全球购物
大学生的网上创业计划书
2013/12/31 职场文书
面试自我评价范文
2014/09/17 职场文书
通报表扬范文
2015/01/17 职场文书
创业计划书之婴幼儿游泳馆
2019/09/11 职场文书
Redis集群的关闭与重启操作
2021/07/07 Redis
一篇文章了解正则表达式的替换技巧
2022/02/24 Javascript
spring boot实现文件上传
2022/08/14 Java/Android