灏天阁

vue3基础组件开发-icon(图标组件)

· Yin灏

前言

使用了 vue3 有很长一段时间了,写了很多的基础组件在自己使用,整理一下(尽量使用最简单的方式实现),当做对自己知识的梳理。

tips: 本文主要是 svg 部分的内容。

技术栈

vue3 + tailwindcss + ts + vite

一个简单的加载图标动画

tailwindcss 中的动画需要配置,所以这里直接把动画 css 拿出来了,具体配置请看官方文档

标签和属性详解:

  1. viewBox=“x y width height”,其中 x 和 y 表示可见区域的左上角坐标,width 和 height 表示可见区域的宽度和高度。使用 viewBox 可以控制 SVG 元素的可见区域,并且可以使得 SVG 元素在不同尺寸的容器中自适应大小,从而避免变形。同时,viewBox 也可以使得 SVG 元素在不同分辨率的设备上呈现出更好的效果
  2. fill=“none”,fill 表示设置 svg 形状的颜色,fill=“none"表示该区域不被填充任何颜色
  3. stroke=“currentColor”,表示边框颜色将使用当前文本颜色或元素的背景颜色,如果当前文本颜色或元素的背景颜色与边框颜色相同,则不会产生任何效果
  4. strokeLinecap=“round”,表示直线结尾是圆形,butt:正常结尾、round:变成圆形、square:变成方形
  5. strokeLinejoin=“round”,表示线的连接是圆润处理,miter:表示正常连接、round:表示连接处为圆润处理、bevel:表示将连接处的尖尖给切除
  6. circle 是绘制圆形
  • cx:圆心的 x 坐标
  • cy:圆心的 y 坐标
  • r:圆的半径 1
<template>
  <svg
    class="loader"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeLinecap="round"
    strokeLinejoin="round"
  >
    <circle cx="12" cy="12" r="10" />
  </svg>
</template>
<style lang="scss" scoped>
.loader {
  // 名称是rotate的动画,无限循环播放(infinite),旋转的速度是线性的(linear),持续时间为2秒
  animation: rotate 2s linear infinite;
}

// 创建一个rotate动画,动作是,旋转360度
@keyframes rotate {
  100% {
    transform: rotate(360deg);
  }
}

.loader circle {
  // 名称是dash的动画,无限循环播放(infinite),先加速后减速(ease-in-out),持续时间是1.5s
  animation: dash 1.5s ease-in-out infinite;
}

@keyframes dash {
  0% {
    // 创建虚线,其中1表示虚线长1,150表示每段虚线之间的间距为150
    stroke-dasharray: 1, 150;
    // 虚线没有设置偏移
    stroke-dashoffset: 0;
  }

  50% {
    // 创建虚线,其中90表示虚线长90,150表示每段虚线之间的间距为150
    stroke-dasharray: 90, 150;
    // 右偏移35个像素
    stroke-dashoffset: -35;
  }

  100% {
    // 创建虚线,其中90表示虚线长90,150表示每段虚线之间的间距为150
    stroke-dasharray: 90, 150;
    // 右偏移124个像素
    stroke-dashoffset: -124;
  }
}
</style>

演示如下(请注意按钮中的转圈圈):

image.png

根据 svg 生成其它图标

在 svg 中很重要的规则:

  1. 一个 svg 里面可以有多个形状标签,详细内容
<svg width="200" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <!-- 方形 -->
  <rect
    x="10"
    y="10"
    width="30"
    height="30"
    stroke="black"
    fill="transparent"
    stroke-width="5"
  />
  <rect
    x="60"
    y="10"
    rx="10"
    ry="10"
    width="30"
    height="30"
    stroke="black"
    fill="transparent"
    stroke-width="5"
  />
  <!-- 圆形 -->
  <circle
    cx="25"
    cy="75"
    r="20"
    stroke="red"
    fill="transparent"
    stroke-width="5"
  />
  <!-- 椭圆 -->
  <ellipse
    cx="75"
    cy="75"
    rx="20"
    ry="5"
    stroke="red"
    fill="transparent"
    stroke-width="5"
  />
  <!-- 线条 -->
  <line x1="10" x2="50" y1="110" y2="150" stroke="orange" stroke-width="5" />
  <!-- 折线 -->
  <polyline
    points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145"
    stroke="orange"
    fill="transparent"
    stroke-width="5"
  />
  <!-- 多边形 -->
  <polygon
    points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180"
    stroke="green"
    fill="transparent"
    stroke-width="5"
  />
  <!-- 路径 -->
  <path
    d="M20,230 Q40,205 50,230 T90,230"
    fill="none"
    stroke="blue"
    stroke-width="5"
  />
</svg>

image.png

  1. 标签元素的渲染顺序是‘后来居上’,也就是说一个 svg 元素里面,越下面的标签层级越高。

  2. 一个 svg 元素内,可以放入多个形状标签。

so,到了这一步,相信很多人都明白了一个 svg 图标该如何制作了,通过在 svg 中定义不同的形状和路径,然后采取移动位置,遮罩和裁剪的方式生成不同的图标图案(类似于 ps 中图层的概念,上面的圆形挡住下面的方形,就形成了一个方形缺口的图案)

当然,你也可以通过路径,去绘制出五花八门的图标(大佬专属)

详细 svg 知识可以点击这里查看

生成图标库使用

一般来说,前端使用图标库,都是如下的使用方式:

<icon type="icon-wx" class="xxx">

class 可以通过 vue3 中的透传的方式传入,具体可以看我上一篇文章# vue3 基础组件开发-button(按钮组件)

如果需要动态属性的话,props 传参,v-bind 就可以实现。

这里主要讲一下,如何把多个含有 svg 单文件组件,统一成 icon 标签使用。

svg 文件的目录结构如下:

|--icons
|  |--wx.vue
|  |--qq.vue
|  |--······
|  |--index.vue

其中,wx.vue 和 qq.vue 分别放着微信和 qq 的图标代码,如下所示:

<--这里是qq.vue-->
<template>
  <svg
    t="1686040405449"
    class="icon"
    viewBox="0 0 1024 1024"
    version="1.1"
    xmlns="http://www.w3.org/2000/svg"
    p-id="1483"
    width="200"
    height="200"
  >
    <path
      d="M824.8 613.2c-16-51.4-34.4-94.6-62.7-165.3C766.5 262.2 689.3 112 511.5 112 331.7 112 256.2 265.2 261 447.9c-28.4 70.8-46.7 113.7-62.7 165.3-34 109.5-23 154.8-14.6 155.8 18 2.2 70.1-82.4 70.1-82.4 0 49 25.2 112.9 79.8 159-26.4 8.1-85.7 29.9-71.6 53.8 11.4 19.3 196.2 12.3 249.5 6.3 53.3 6 238.1 13 249.5-6.3 14.1-23.8-45.3-45.7-71.6-53.8 54.6-46.2 79.8-110.1 79.8-159 0 0 52.1 84.6 70.1 82.4 8.5-1.1 19.5-46.4-14.5-155.8z"
      p-id="1484"
    ></path>
  </svg>
</template>

在 index.vue 实现以下代码,即可实现上面 type=“qq” 就是选择使用 qq.vue 的 svg 图标的效果:

<--这里是index.vue-->
<template>
  <component :is="icon" />
</template>

<script setup lang="ts">
const props = defineProps({
  type: { type: String, required: true },
});

// 这里也可以请求服务器,如果图标非常多的话,可以维护一个自己的静态资源服务器,从服务器异步请求回来显示
const icon = defineAsyncComponent(() => import("./" + props.type + ".vue"));
</script>

使用:

<template>
  <icon type="qq"></icon>
</template>

<script setup lang="ts">
import icon from "@/icons";
</script>

效果如下图所示

image.png

ok,如果我们要改变图标的颜色呢,直接在 icon 标签上添加属性就可以了,如下:

<template>
  <icon fill="red" type="qq"></icon>
</template>

效果如下图所示:

image.png

同理,我们想要改变宽高,直接加载 icon 标签上就可以了,如下:

<template>
  <icon width="100" height="100" fill="red" type="qq"></icon>
</template>

效果如下所示:

image.png

原理就是 vue3 中的属性透传

尾声

使用 svg 图标的好处,就不用我多说了,懂的都懂。如有错漏之处,欢迎各位大佬指正。

- Book Lists -