精读 Vue 官方文档系列 🎉
基本的示例
一个 .svg 文件的内容如下所示:
<svg t="1626687392304" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1062"
width="200" height="200">
<path
d="M512 1024a512 512 0 1 1 512-512 512 512 0 0 1-512 512z m-0.674909-932.398545A419.653818 419.653818 0 1 0 930.909091 511.255273 419.653818 419.653818 0 0 0 511.255273 91.601455z m139.892364 372.852363h93.765818v94.743273h-93.765818v-94.743273z m-186.181819 0h93.765819v94.743273h-93.765819v-94.743273z m-186.181818 0h93.765818v94.743273h-93.765818v-94.743273z"
fill="#565656" p-id="1063"></path>
</svg>
一般使用 .svg 的方式有两种::
- 像引入图片一般,用
img标签的src属性来引入一个svg文件。 - 直接将
<svg>...</svg>标签引入到 HTML 文件中。
由于第一种方式使用条件较为苛刻,且不利于工程化处理,因此第二种方式更常用,将每个.svg 文件都视为一个独立的模块来处理。
观察 svg 代码,可以发现有两个重要标签 <svg/> 与 <path/>, 其中 <path/> 描述了具体的矢量路径,它代表了实际的图形。而 <svg/> 标签相对来说比较固定,可以控制图形的宽、高、viewbox 等。现在基于观察后的结果,我们就可以创建“可编辑的 SVG 图标系统”了,首先对 <svg/> 标签进行封装,通过外部 props 来控制其属性,然后以插槽(slot)的方式来动态引入 <path/> 标签。
“可编辑的 SVG 图标系统”的优点:
- 图标易于实时修改。
- 图标可以带动画。
- 图标是内联的,所以不需要额外的 HTTP 请求。
- 可以动态地使得图标可访问
具体实践,先定义充当标签的容器 IconBase.vue 组件。
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 18 18"
:width="width"
:height="height"
:aria-labelledby="iconName"
role="presentation"
>
<title lang="en" :id="iconName">{{ iconName }} icon</title>
<g :fill="iconColor">
<slot />
</g>
</svg>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "IconBase",
props: {
width: {
type: [Number, String],
default: 18,
},
height: {
type: [Number, String],
default: 18,
},
iconName: {
type: String,
default: "",
},
iconColor: {
type: String,
default: "currentColor",
},
},
});
</script>
然后来定义具体的 svg 图标组件:IconSymbol.vue
<template>
<path
d="M512 1024a512 512 0 1 1 512-512 512 512 0 0 1-512 512z m-0.674909-932.398545A419.653818 419.653818 0 1 0 930.909091 511.255273 419.653818 419.653818 0 0 0 511.255273 91.601455z m139.892364 372.852363h93.765818v94.743273h-93.765818v-94.743273z m-186.181819 0h93.765819v94.743273h-93.765819v-94.743273z m-186.181818 0h93.765818v94.743273h-93.765818v-94.743273z"
></path>
</template>
最后来组合两个组件进行使用:
<icon-base :width="18" :height="18" :icon-name="symbol">
<icon-symbol/>
</icon-base>
当然,你也可以直接在
iconBase.vue中基于传入的icon-name来动态匹配对应的图标组件,以减少一层封装。
带动画的图标
文章给的思路很简单,使用动画库例如 gsap 然后用 $refs 来直接操作 DOM 的方式为 <path/> 标签赋予动画效果。
其它替代方案
直接在页面中引入 <svg> 内容的另一种使用方式,就是 Svg Sprite 了,简称 SVG 精灵。
你可以配置 Webpack 的 svg-sprite-loader 来一次性的将所有 svg 内容注入到 HTML 文件中,并为每个 symbol 设置 ID,最后只需要使用 <use xlink="iconId"> 标签来引入对应 symbol 的 Id 即可。
这种方式可以避免重复多次的向 HTML 插入 Svg 代码,例如在表格与列表渲染 svg 内容时。
但是带来的不足也很明显,那就是一旦 svg 内容过多,就会导致页面加载缓慢,或者是导致编译工具编译速度变慢。
最后,文章还分享了另一个 SVG 相关的工具:svgo-loader 可以对 SVG 的代码进行优化与精简,例如删除无用的注释与属性。