在Vue.JS中使用图标组件

更新日期: 2020-08-02阅读: 2.4k标签: 图标
原文链接: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形态,它们有各自的优缺点:

使用单一的组件(如<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)

用一个单一的维护(如<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的缺点。

每个组件代表不同的图标(如<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)

作者:张立理 百度资深前端工程师


链接: https://fly63.com/article/detial/9549

html中为何经常使用<i>标签来作为小图标呢?

很多网站都是习惯使用<i></i>来代表小图标?而实际上用 <i> 元素做图标在语义上是不正确的(虽然看起来像 icon 的缩写),那么用<i>表示小icon,是出于好记的原因吗,还是看上去有点像icon?这样不是违背了语义化的原则吗?

微信分享图标设置,以及wx.config配置

页面分享微信显示小图和描述的功能,微信就会抓取这张图片做为分享图片,微信对自定义分享内容作了限制,于是最终还是得回到配置wx.config上来。

利用伪元素:before和:after插入图标

如果你想在网页的某些文字前加图标或者想改变li元素默认的图标,你会如何做?本文价绍一种不用再额外添加html标签,存粹利用css就能插入或者自作图标的方式。

HTML中title前面小图标的实现_如何给网页标题添加icon小图标

今天给大家分享的是如何在网页标题中加入小图标,你的图标格式最好是.ico格式的,为了兼容性考虑,使用的颜色不要超过16色,这里这个图标的命名要求必须为favicon.ico

css图标库_css常用的矢量图标大全

这篇文章主要介绍前端常用的css图标库有哪些?比如:阿里巴巴矢量图标库Iconfont、Font Awesome、Cikonss、Glyph Icons、Simple Line Icons等等,使用css图标,可以通过样式对他进行设置字体颜色,大小等

网页中favicon.ico图标的作用、尺寸、制作

网站favicon.ico文件的用途很简单,就是在浏览器标签里,最前面显示的那个logo,对于网站 favicon.ico 图标的大小,建议大家选择 16x16 或者 32x32,再大也是完全没有必要的。favicon.ico

图标使用新姿势- react 按需引用 svg 的实现

图标是前端在业务开发中不得不写的一个东西,以我司的几个部门为例,每个组在写图标上都有不一样的方式:用户平台:单色图标用 iconfont 上提供的字体文件,彩色图标用 img 引入代替或者使用iconfont 上提供的 symbol.js 。

font-awesome图标转为图片

font-awesome图标是字体,专业术语叫 Icon Font,本质上是使用 PUA ( Private Unicode Area )码位 Unicode 编码的字符,所以font-awesome图标、Bootstrap 的图标和 Wingdings 字体都是一样的,不一样的无非是编码。

Bootstrap图标

小图标icon是一个优秀Web中不可缺少的一部分,起到画龙点睛的效果。在Bootstrap框架中也为大家提供了250多个不同的icon图片。本文将详细介绍Bootstrap图标,Bootstrap框架中的图标都是字体图标

纯css制作电闪雷鸣的天气图标

使用box-shadow属性写几个圆,将这些圆错落的组合在一起,形成云朵图案;after伪元素写下面的投影样式;before伪元素写黄色闪电的样式;用两个嵌套的div容器就可以了,父容器来控制图标显示的位置

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!