1. 程式人生 > 程式設計 >如何在Vue.JS中使用圖示元件

如何在Vue.JS中使用圖示元件

原文連結: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,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,setup() {
 const flag = ref(true)

 return {
  flag,IconFlag,IconStar
 }
 }
}
</script>

如果用:is繫結,<script>部分會變成這樣:

import { ref } from 'vue'
import { IconFlag,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中使用圖示元件的資料請關注我們其它相關文章!