在婚戀app原始碼開發中,如何實現滑動驗證碼元件?

雲豹科技程式設計師發表於2021-10-11

前言

滑動驗證碼相信大家肯定會經常遇到,其實在婚戀app原始碼開發時,我們也可以實現該功能,這樣就能更好的保護使用者資訊和平臺資料的安全,具體應該如何做呢?

技術實現

接下來將會以我的思路來帶大家在婚戀app原始碼中實現滑動驗證碼元件。

1. 明確功能

在開發前我們首先要明確要實現哪些功能:

1、隨機圖片(這裡不做過多描述,採用Picsum實現)
2、位置隨機的鏤空圖案繪製
3、利用canvas進行圖案裁剪
4、可滑動控制的拖拽滑塊
5、圖片載入時的loading效果
6、在婚戀app原始碼中能實現重新整理按鈕的點選
7、驗證拖拽位置是否滿足要求
在這裡插入圖片描述

2. 基本框架

我們先搭建出基本的框架

<div v-if="visiblity" class="slidingWrap">
    <div class="slidingTitle"></div>
    <!-- 畫布區域 -->
    <div class="canvasArea">
      <!-- 主要渲染整體背景及鏤空圖案 -->
      <canvas class="canvas-bg" :width="width" :height="height"></canvas>
      <canvas
        class="block"
        :height="height"
        :style="{ left: `${blockLeft}px` }"
      ></canvas>
    </div>
    <!-- 底部滑塊 -->
    <div      :class="['sliderWrap', status]"
      :style="{ width: `${width}px` }"
      @mouseleave="handleDrapUp"
    >
      <div
        class="progress"
        :style="{
          width: `${blockLeft}px`        }"      ></div>
      <div
        class="slider-block"
        ref="slider"
        :style="{ left: `${blockLeft}px` }"
        @mousedown="handleDrapDown"
        @mouseup="handleDrapUp"
        @mousemove="handleDragMove"
      >
        &rarr;
      </div>
    </div>
    <!-- 重新整理按鈕 -->
    <div class="refresh" @click="onRefreshBtnClick"></div>
    <!-- 載入中提示 -->
    <div
      class="loading"
      v-show="isLoading"
      :style="{ width: `${width}px`, height: `${height}px` }"
    >
      <img
        src="
        alt=""
      />
      載入中...
    </div>
  </div>

然後定義一些支援婚戀app原始碼配置的屬性

  props: {
    // 元件是否可見
    visiblity: {
      type: Boolean,
      default: false    },
    // 元件的寬度
    width: {
      type: Number,
      default: 300
    },
    // 元件的高度
    height: {
      type: Number,
      default: 200
    },
    // 滑塊的長度
    l: {
      type: Number,
      default: 42
    },
    // 滑塊的半徑
    r: {
      type: Number,
      default: 9
    },
    // 滑塊的容錯值
    tolerant: {
      type: Number,
      default: 5
    },
    // 成功時的回撥
    onSuccess: {
      type: Function,
      default: () => {}
    },
    // 重新整理時的回撥
    onRefresh: {
      type: Function,
      default: () => {}
    },
    // 失敗時的回撥
    onFail: {
      type: Function,
      default: () => {}
    },
    // 關閉回撥
    closed: {
      type: Function,
      default: () => {}
    }

3.實現鏤空效果的圖片

在這裡插入圖片描述
上圖我們可以發現是一個不規則的圖形,下面簡單畫一個草圖
在這裡插入圖片描述
在開始之前,我們首先要了解用到的api:

  • beginPath(): 當你想建立一個新的路徑時,呼叫此方法
  • moveTo(): 將一個新的子路徑的起始點移動到(x,y)座標的方法
  • arc(): 繪製圓弧路徑的方法
  • lineTo(): 使用直線連線子路徑的終點到x,y座標的方法
  • stroke(): 描邊
  • fill(): 填充
  • clip(): 裁剪
  • save():通過將當前狀態放入棧中,儲存 canvas 全部狀態的方法。
  • restore():通過在繪圖狀態棧中彈出頂端的狀態,將 canvas 恢復到最近的儲存狀態的方法。
  • getImageData():返回一個ImageData物件,用來描述canvas區域隱含的畫素資料
  • putImageData():將資料從已有的 ImageData 物件繪製到點陣圖的方法
  • drawImage():在canvas上繪製影像。

程式碼實現如下:

drawPath(x, y, l, r, ctx, operation) {
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.arc(x + l / 2, y - r + 2, r, 0.72 * Math.PI, 2.26 * Math.PI);
      ctx.lineTo(x + l, y);
      ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * Math.PI, 2.78 * Math.PI);
      ctx.lineTo(x + l, y + l);
      ctx.lineTo(x, y + l);
      // anticlockwise為一個布林值。為true時,是逆時針方向,否則順時針方向
      ctx.arc(
        x + r - 2,
        y + l / 2,
        r + 0.4,
        2.76 * Math.PI,
        1.24 * Math.PI,
        true      );
      ctx.lineTo(x, y);
      ctx.lineWidth = 2;
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
      ctx.stroke();
      ctx.globalCompositeOperation = "destination-over";
      // 判斷是填充還是裁切, 裁切主要用於生成圖案滑塊
      operation === "fill" ? ctx.fill() : ctx.clip();
    }

通過該方法我們可以在canvas中畫出對應的圖案,細心的同學可以發現,我們在body中寫了兩個canvas標籤,那麼他們的作用分別是什麼呢?

  • canvas-bg主要功能是繪製背景圖片和鏤空圖案
  • block主要功能是對圖案進行裁剪並進行移動

4、初始化函式

/**
     * 1. 隨機獲取到圖片
     * 2. 隨機生成圖片滑塊位置
     * 3. 擷取圖片並移動到初始位置
     * 4. 畫出鏤空圖案
     * 5. 拿到下方滑塊的初始位置
     */
    initCanvas() {
      // 拿到canvas物件
      let canvas = document.getElementsByClassName("canvas-bg")[0];
      let blockcanvas = document.getElementsByClassName("block")[0];
      // 畫筆
      let ctx = canvas.getContext("2d");
      let blockCtx = blockcanvas.getContext("2d");
      // 每次重新繪製圖片時,清除畫布原有內容
      ctx.clearRect(0, 0, this.width, this.height);
      blockcanvas.width = this.width;
      // 生成image物件
      let img = new Image();
      // 解決跨域問題
      img.crossOrigin = "";
      img.onload = () => {
        ctx.drawImage(img, 0, 0);
        blockCtx.drawImage(img, 0, 0);
        this.isLoading = false;
        const ImageData = blockCtx.getImageData(x, y1, this.l + 2 * this.r, y);
        // 裁剪後重置畫布的狀態
        blockCtx.restore();
        blockcanvas.width = this.l + 2 * this.r;
        blockCtx.putImageData(ImageData, 0, y1);
      };
      // 圖片訪問地址,後面增加時間戳,防止拿快取
      img.src = `{this.width}/${
        this.height      }?time=${+new Date()}`;
      // x y 位置隨機
      let { x, y } = this.getXY();
      this.drawPath(x, y, this.l, this.r, ctx, "fill");
      // 裁剪前儲存畫布的狀態
      blockCtx.save();
      this.drawPath(x, y, this.l, this.r, blockCtx, "clip");
      const y1 = y - this.r * 2 - 1;
    }

我們知道,婚戀app原始碼中滑動驗證碼的主要功能就是判斷是否人為操作,我們通常採用的方式就是隨機驗證,這裡我們前端採用Math.random()方法進行實現,更安全的做法是通過後端進行返回,生成隨機位置的函式如下:

    // 隨機生成滑塊的目標位置
    getXY() {
      let x =
        this.width / 3 +
        Math.random() * ((this.width * 3) / 4 - this.width / 3);
      let y =
        this.height / 3 +
        Math.random() * ((this.height * 3) / 5 - this.height / 3);
      this.x = x;
      return { x, y };
    }

這裡限制了位置座標的範圍,讓滑塊的目標位置更加的合理,讓目標位置在白色區域範圍內:
在這裡插入圖片描述
5.滑塊的拖拽

完成以上程式碼後,頁面佈局基本為這個樣子:
在這裡插入圖片描述
觀察我們可以發現,我們拖拽下方箭頭時,block跟隨滑塊移動即可,那麼如何在婚戀app原始碼中實現一個滑塊的拖拽呢?

我們可以想一下拖拽動作是如何發生的,按下滑鼠左鍵後移動滑鼠即可拖拽,滑鼠釋放完成拖拽,我們可以把它分解為三個動作:mousedown、mousemove、mouseup,我們監聽三個動作即可完成相應的操作。

   handleDragMove(e) {
      if (!this.isDrop) return false;
      e.preventDefault();
      // 獲取滑鼠位置
      const eventX = e.clientX || e.touches[0].clientX;
      let moveX = eventX - this.blockInitLeft - 20;
      // 對滑塊的位置進行風控處理
      if (moveX < 0 || moveX + 40 + 2 * this.r > this.width) return false;
      // 設定滑塊的的位置及進度條的寬度
      this.blockLeft = moveX;
    },
    // 初始化未完成時,不可滑動
    // 滑動開始時,將狀態置為等待狀態
    handleDrapDown() {
      if (this.isLoading) return;
      this.isDrop = true;
      this.status = "wait";
    },
    // 拖拽動作完成之後執行
    handleDrapUp() {
      if (!this.isDrop) return;
      this.isDrop = false;
      // 判斷是否拖拽的指定位置
      let val = Math.abs(this.x - this.blockLeft);
      this.status = val > this.tolerant ? "fail" : "success";
      // 執行相應的生命週期函式
      if (this.status === "fail") {
        this.onFail();
      } else {
        this.onSuccess();
      }
      // 1s後觸發關閉回撥或者重新整理動作
      setTimeout(() => {
        if (this.status === "success" && this.visiblity) {
          this.closed();
          return;
        }
        this.handleRefresh();
      }, 1000);
    }

最後

婚戀app原始碼的滑塊驗證碼元件大致功能已經完成,還有一些細節方面需要優化,希望以上內容能給大家帶來幫助。

本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理
原文連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2795380/,如需轉載,請註明出處,否則將追究法律責任。

相關文章