原文链接: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 " /> </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 " /> </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 " /> </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 " /> </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中使用图标组件的资料请关注其它相关文章!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 2019明达发烧碟MasterSuperiorAudiophile[WAV+CUE]
- 蔡幸娟.1993-相爱容易相处难【飞碟】【WAV+CUE】
- 陆虎.2024-是否愿意成为我的全世界【Hikoon】【FLAC分轨】
- 关淑怡.2009-ERA【星娱乐】【WAV+CUE】
- 林忆莲《关于她的爱情故事》2022新世纪MQA 24K金碟限量版[WAV+CUE]
- 张雨生1993《一天到晚游泳的鱼》台湾G字首版[WAV+CUE][1G]
- 群星《试音五大女声》[WAV+CUE][1G]
- 魔兽世界wlk武器战一键输出宏是什么 wlk武器战一键输出宏介绍
- 魔兽世界wlk狂暴战一键输出宏是什么 wlk狂暴战一键输出宏介绍
- 魔兽世界wlk恶魔术士一键输出宏是什么 wlk恶魔术士一键输出宏介绍
- 医学爱好者狂喜:UP主把医学史做成了格斗游戏!
- PS5 Pro评分解禁!准备升级入手吗?
- 我们盘点了近期火热的国产单机游戏!《琉隐神渡》等 你期待哪款?
- 2019年第12届广州影音展双碟纪念版ADMS2CD[MP3/WAV]
- 黄安《救姻缘》台首版[WAV+CUE]