Original link:/Justineo/fb2ebe773009df80e80d625132350e30
This article translates the original text and briefly interprets it from the perspective of React developers.
This article does not contain font icons and SVG sprite. This is only discussed here that allows users to import on demand.
There are three major ways of exposing API of an icon component in and each one of them has its own pros & cons:
In the ecosystem, there are three mainstream API forms, and they have their own advantages and disadvantages:
1. Use a single component (such as <v-icon>), and Jean uses the name or type attribute to specify the real icon.
The icon data is registered through a global "pool".
// v-icon/ import Icon from 'v-icon' import { mdiFlag } from '@mdi/js' ('flag', mdiFlag)
Then use it like this:
<template> <v-icon name="flag" /> </template> <script> import VIcon from 'v-icon' import 'v-icon/flag' export default { components: { VIcon } } </script>
In my maintenanceVueAwesome(The component library with built-in FontAwesome icon) is used in this solution, and I think this is the most ergonomic form at present. However, the relationship between the name attribute of the icon and the import of those modules with pure side effects is relatively implicit, and the icon data is also registered globally. If you have multiple different versions of v-icon, problems may arise.
FontAwesome officialThe components use a slightly different scheme, which allows the user to actively add icons to the global pool (or maybe I shouldn't classify this method into this scheme):
import { library } from '@fortawesome/fontawesome-svg-core' import { faUserSecret } from '@fortawesome/free-solid-svg-icons' (faUserSecret)
2. With a single maintenance (such as <v-icon), the user creates real icons through attributes such as data or content.
The user actively passes the icon data to the component:
<template> <v-icon :content="mdiFlag" /> </template> <script> import VIcon from 'v-icon' import { mdiFlag } from '@mdi/js' export default { components: { VIcon }, created() { (this, { mdiFlag }) } } </script>
This is the way Vuetify supports (Vuetify supports the use of multiple icons in this way), which has some losses in ergonomics and intuitiveness, but does not have the disadvantages of Solution 1.
3. Each component represents a different icon (such as <icon-flag />, <icon-star />, etc.).
In this solution, each component is created through an icon factory:
// import { mdiFlag } from '@mdi/js' import { createIcon } from 'v-icon' export default createIcon('flag', mdiFlag)
And use this way:
<template> <icon-flag /> </template> <script> import { IconFlag } from 'v-icon' export default { components: { VIcon, IconFlag } } </script>
This solution is widely adopted in the React community and I will discuss it later in this article.
Each component represents an icon
I will talk more deeply about the use of this solution.
In, the template and script are separated, and the components are registered through the components option. But as we know, if a component uses a lot of icons, this method will be quite troublesome.
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() { (this, { IconFlag, IconStar }) } } </script>
You can see that if you want to use the is bound by the icon, we must manually expose the components to the rendering context. We can use strings to replace component definitions to bypass it, but it is not so friendly to code checking and type systems.
<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>
If you use :is, the <script> part will become like this:
import { ref } from 'vue' import { IconFlag, IconStar } from 'foo-icons' export default { components: { IconFlag, IconStar }, setup() { const flag = ref(true) return { flag } } }
If we adopt the form <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>
Or use <script setup> to propose:
<script setup> import { ref } from 'vue' export const flag = ref(true) </script>
postscript
This article carefully introduces the way to introduce icons on demand in Vue. Compared with the React community, we can see that the differences between the two ecology still exist. In the React community, the third method (one component per icon) is very common, such as the high-ranking react-icons on NPM and the well-known component libraries @ant-design/icons and @material-ui/icons are all in this form.
This may be because the React community does not tend to specialize the concept of "component". Components are ordinary functions and ordinary classes, so their replication of other functions and classes is the same. Just as lodash will export many tool functions, it is very reasonable for an icon library to export many icon components.
There are some points in the article that can be optimized for the use of createIcon factory functions. Normal use of factory functions will prevent the created components from being tree shaking. The reason is that syntax analysis will believe that the createIcon function itself has side effects, so this call cannot be safely deleted. It can be marked with the terser's special comment:
// import { mdiFlag } from '@mdi/js' import { createIcon } from 'v-icon' export default /*#__PURE__*/createIcon('flag', mdiFlag)
The above is the detailed content of how to use icon components in the process. For more information about using icon components in the process, please pay attention to my other related articles!