本文为稀土技能社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究

前言

hello, 咱们好, 我是徐小夕, 今日又到了咱们的博学时刻。

本文是 100+前端几许学应用案例 专栏的第五篇文章, 之前和咱们共享了怎么从零完成几许画板以及几许画板的吊销 / 重做 / 图层办理等功用:

  • 几许学在前端鸿沟计算中的应用和原理分析
  • 前端图形学实战: 从零开发几许画板(vue3 + vite版)
  • 前端图形学实战: 100行代码完成几许画板的吊销重做等功用(vue3 + vite版)
  • 前端图形学实战: 从零完成编辑器的图层办理面板和实时缩略图(vue3 + vite版)

今日和咱们共享一个新的图形学实战——滑动验证码的完成

你将收获

  • vue3组件的规划思路和技巧
  • canvas的常用绘图api用法
  • 滑动验证码组件的基本规划原理和完成过程
  • 怎么从零发布vue3组件库

作用演示

依照笔者的写作习惯, 这儿先和咱们演示一下完成的作用:

正文

这篇文章我会带咱们运用 vue3 + vite 来完成滑动验证码, 当然笔者之前也完成了基于 react 的滑动验证码组件, 感兴趣的能够参阅我之前的文章:

  • 从零开发一款轻量级滑动验证码插件

同时也能够在 github 上检查到对应的完成代码:

github.com/MrXujiang/v…

技能完成

在着手开发组件之前咱们需求提早明晰组件的规划需求, 并拟定合理的开放 api, 这儿共享一下我总结的组件高雅规划的原则:

  • 可读性(代码格式统一明晰,注释完好,代码结构层次分明,编程范式运用得当)

  • 可用性(代码功用完好,在不同场景都能很好兼容,事务逻辑覆盖率)

  • 复用性(代码能够很好的被其他事务模块复用)

  • 可维护性(代码易于维护和扩展,并有一定的向下/向上兼容性)

  • 高性能(组件具有一定的性能, 如复杂场景的烘托, 计算等)

而咱们滑动验证码组件要想让更多的人运用, 就必须做到一定程度的灵活可装备, 接下来是我总结的滑动验证码的中心 api:

  • 操控滑动验证码的显示隐藏(visible)
  • 操控滑动验证码的大小(width 和 height)
  • 操控滑块的样式(边长 l 和半径 r)
  • 滑块的提示文本(text)
  • 滑动验证码的图片数据源(imgUrls)
  • 验证成功的事情回调(onSuccess)
  • 验证失利的事情回调(onFail)
  • 用户自界说的验证逻辑(onCustomVertify)
  • 用户拖拽滑块时的回调(onDraw)
  • 改写图片时的回调(onRefresh)

对应图示如下:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

特点功用规划好之后咱们来构想一下在vue项目中详细的运用方法:

<template>
  <div>
    <vertify 
      width="200" 
      height="80" 
      l="50" 
      r="5"
    ></vertify>
  </div>
</template>
<script setup>
// 事务逻辑...
</script>

以上基础准备好之后咱们来可看一下滑动验证码的详细交互流程:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

1.规划滑动验证码的基本骨架

这儿我以vue3组合函数的方法来界说一下 vue-slider-veritfy 组件骨架:

<script lang="ts" setup>
import { ref, watch, onMounted } from "vue";
interface VertifyType {
  spliced: boolean;
  verified: boolean; // 简单验证拖动轨道,为零时表示Y轴上下没有动摇,或许非人为操作
  left: number; // 滑块的移动方位
  destX: number; // 滑块的方针方位
}
interface IProps {
  width?: number;
  visible?: boolean;
  height?: number;
  refreshIcon?: string;
  l?: number;
  r?: number;
  imgUrl?: string;
  text?: string;
  /**
   * @description   拖拽滑块时的回调, 参数为当前滑块拖拽的间隔
   * @default       (l: number):void => {}
   */
  onDraw?: (l: number) => {};
  /**
   * @description   用户的自界说验证逻辑
   * @default       (arg: VertifyType) => VertifyType
   */
  onCustomVertify?: (arg: VertifyType) => VertifyType;
  /**
   * @description   重制改写前的回调
   * @default       ():void => {}
   */
  onBeforeRefresh?: () => void;
  /**
   * @description   验证成功回调
   * @default       ():void => {}
   */
  onSuccess?: VoidFunction;
  /**
   * @description   验证失利回调
   * @default       ():void => {}
   */
  onFail?: VoidFunction;
  /**
   * @description   改写时回调
   * @default       ():void => {}
   */
  onRefresh?: VoidFunction;
}
// 界说默认值
const props = withDefaults(defineProps<IProps>(), {
  width: 320,
  visible: true,
  height: 160,
  refreshIcon: "",
  l: 42,
  r: 9,
  imgUrl: "",
  text: "",
});
// 构建dom结构
<template>
  <div
    className="vertifyWrap"
  >
    <div className="canvasArea">
      <canvas ref="canvasRef"></canvas>
    </div>
    <div
      :className="sliderClass"
    >
      <div className="sliderMask">
        <div
          className="slider"
        >
          <div className="sliderIcon">&rarr;</div>
        </div>
      </div>
      <div className="sliderText">{{ textTip }}</div>
    </div>
    <div
      className="refreshIcon"
    ></div>
    <div
      className="loadingContainer"
    >
      <div className="loadingIcon"></div>
      <span>加载中...</span>
    </div>
  </div>
</template>

上面代码需求留意的便是 withDefaultsdefineProps , defineProps 首要用来界说 vue 组件的特点类型, withDefaults 能够用来界说组件特点的默认值, 这也是在规划 vue3 组件中常用的 api

2. 滑动验证码中心功用完成

接下来咱们需求完成以下几个中心功用:

  • 镂空作用的 canvas 图片完成
  • 镂空图画 canvas 完成
  • 滑块移动和验证逻辑完成

上面的描述或许比较抽象,我画张图示意一下:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

在开始编码之前咱们需求对 canvas 有个基本的了解,主张不熟悉的朋友能够参阅高效 canvas 学习文档: Canvas of MDN。

由上图可知首先要解决的问题便是怎么用 canvas 画不规则的图形,这儿我简单的画个草图:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

咱们只需求运用 canvas 供给的 途径api 画出上图的途径,并将途径填充为恣意半透明的色彩即可。主张咱们不熟悉的能够先了解如下 api :

  • beginPath() 开始途径绘制
  • moveTo() 移动笔触到指定点
  • arc() 绘制弧形
  • lineTo() 画线
  • stroke() 描边
  • fill() 填充
  • clip() 裁切途径

因为完成方法比较固定, 偏 canvas 语法层, 这儿直接共享一下代码:

const drawPath = (ctx: any, x: number, y: number, operation: "fill" | "clip") => {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
  ctx.lineTo(x + l, y);
  ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
  ctx.lineTo(x + l, y + l);
  ctx.lineTo(x, y + l);
  ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
  ctx.lineTo(x, y);
  ctx.lineWidth = 2;
  ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
  ctx.strokeStyle = "rgba(255, 255, 255, 0.7)";
  ctx.stroke();
  ctx.globalCompositeOperation = "destination-over";
  operation === "fill" ? ctx.fill() : ctx.clip();
};

这儿需求补充的一点是 canvasglobalCompositeOperation 特点,它的首要目的是设置怎么将一个源(新的)图画绘制到方针(已有)的图画上。

  • 源图画 = 咱们打算放置到画布上的绘图

  • 方针图画 = 咱们现已放置在画布上的绘图

w3c上有个形象的例子:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

这儿之所以设置该特点是为了让镂空的形状不受背景底图的影响并覆盖在背景底图的上方。如下:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

接下来咱们只需求将图片绘制到画布上即可:

const canvasCtx = canvasRef.current.getContext('2d')
// 绘制镂空形状
drawPath(canvasCtx, 50, 50, 'fill')
// 画入图片
canvasCtx.drawImage(img, 0, 0, width, height)

接下来咱们只需求用 javascript 完成随机图片和随机方位即可。

咱们再来完成一下镂空作用:

const blockCtx = blockRef.value.getContext('2d')
drawPath(blockCtx, 50, 50, 'clip')
blockCtx.drawImage(img, 0, 0, width, height)
// 提取图画滑块并放到最左边
const y1 = 50 - r * 2 - 1
const ImageData = blockCtx.getImageData(xRef.value - 3, y1, L, L)
// 调整滑块画布宽度
blockRef.value.width = L
blockCtx.putImageData(ImageData, 0, y1)

上面的代码咱们用到了 getImageDataputImageData,这两个 api 首要用来获取 canvas 画布场景像素数据和对场景进行像素数据的写入。完成后 的作用如下:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

完成滑块移动和验证逻辑

完成滑块移动的计划也比较简单,咱们只需求利用鼠标的 event 事情即可:

  • onMouseDown
  • onMouseMove
  • onMouseUp

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

以上是一个简单的示意图,详细完成代码如下:

const handleDragMove = (e) => {
    if (!isMouseDownRef.value) return false
    e.preventDefault()
    // 为了支持移动端, 能够运用e.touches[0]
    const eventX = e.clientX || e.touches[0].clientX
    const eventY = e.clientY || e.touches[0].clientY
    const moveX = eventX - originXRef.value
    const moveY = eventY - originYRef.value
    if (moveX < 0 || moveX + 36 >= width) return false
    sliderLeft.value = moveX;
    const blockLeft = (width - l - 2r) / (width - l) * moveX
    blockRef.value.style.left = blockLeft + 'px'
}

当然咱们还需求对拖拽中止后的事情做监听,来判别是否验证成功,并埋入成功和失利的回调。

咱们发现 vue3 版别的完成和我之前的 react 版别的方法相似, 首要差异就在于 api 用法和界说上, 这儿共享一下详细的变量界说:

const {
  text,
  l,
  r,
  imgUrl,
  width,
  height,
  visible,
  onBeforeRefresh,
  onRefresh,
  onFail,
  onSuccess,
  onCustomVertify,
  onDraw,
} = props;
const isLoading = ref(false);
const sliderLeft = ref(0);
const sliderClass = ref("sliderContainer");
const textTip = ref(text);
const canvasRef = ref<any>(null);
const blockRef = ref<any>(null);
const imgRef = ref<any>(null);
const isMouseDownRef = ref<boolean>(false);
const trailRef = ref<number[]>([]);
const originXRef = ref<number>(0);
const originYRef = ref<number>(0);
const xRef = ref<number>(0);
const yRef = ref<number>(0);
const PI = Math.PI;
const L = l + r * 2 + 3; // 滑块实际边长

完好的完成作用如下:

将完成的滑动验证码组件发布到 npm 上

发布流程我在 从零开发一款轻量级滑动验证码插件 有详细的介绍, 接下来给咱们展现一下经过 vite 打包组件包的装备:

export default defineConfig({
  ...baseConfig,
  build: {
    outDir: 'dist',
    lib: {
      entry: resolve(__dirname, '../packages/index.ts'),
      name: 'vue-slider-vertify',
      fileName: (format) => `vue-slider-vertify.${format}.js`,
    },
    rollupOptions: {
      // 确保外部化处理不想打包进库的依赖
      external: ['vue'],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖供给一个全局变量
        globals: {
          vue: 'Vue'
        }
      }
    }
  },
  plugins: [
    ...(baseConfig as any).plugins,
    dts(),
  ]
});

打包后的 dist 目录结构如下:

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

假如咱们想了解详细的源码和打包过程, 能够在 github 上检查完好代码, 地址如下:

github.com/MrXujiang/v…

假如咱们想经过 npm 的方法直接运用, 能够用我现已发布到 npm 服务器的 react-slider-vertify, 依照如下方法装置和运用:

# 或者 npm add @alex_xu/react-slider-vertify
yarn add @alex_xu/react-slider-vertify

在代码里运用:

import React from 'react';
import { Vertify } from '@alex_xu/react-slider-vertify';
export default () => {
    return <Vertify 
            width={320}
            height={160}
            onSuccess={() => alert('success')} 
            onFail={() => alert('fail')} 
            onRefresh={() => alert('refresh')} 
        />
};

前端图形学实战: 从零开发一款轻量级滑动验证码组件(vue3 + vite版)

扩展

咱们也能够基于自己的事务需求改造咱们的验证码, 完成更负复杂的功用, 改造成多种形态的验证码, 也欢迎咱们随时奉献, 一同打造非常有意思的验证码组件。

后期规划

后面会持续环绕图形可视化来完成更多有意思的应用, 比方3D可视化, 图形编辑器, 可视化图表等, 假如咱们感兴趣, 能够参阅我的github: gitee.com/lowcode-chi…

假如文章对你有帮助, 欢迎点赞评论, 让咱们一同探究真实的前端技能。

更多引荐

(10月最新) 前端图形学实战: 从零开发几许画板(vue3 + vite版)

Dooring无代码搭建渠道技能演进之路

从零开发一款可视化大屏制作渠道

从零开发一款图片编辑器Mitu