成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從零開發一款輕量級滑動驗證碼插件(深度復盤)

開發 前端
今天繼續和大家分享一款非常有趣且實用的前端實戰項目——從零基于 react + canvas 實現一個滑動驗證碼,并將其發布到 npm 上供他人使用。

[[425863]]

之前一直在分享 低代碼 和 可視化 的文章,其中涉及到很多有意思的知識點和設計思想,今天繼續和大家分享一款非常有趣且實用的前端實戰項目——從零基于 react + canvas 實現一個滑動驗證碼,并將其發布到 npm 上供他人使用。當然如果大家更喜歡 vue 的開發方式,也不用擔心,文中的設計思想和思路都是通用的,如果大家想學習如何封裝 vue 組件并發布到 npm 上,也可以參考我之前的文章: 從零到一教你基于vue開發一個組件庫。

從這個實戰項目中我們可以學到如下知識點:

  • 前端組件設計的基本思路和技巧
  • canvas 基本知識和使用
  • react hooks 基本知識和使用
  • 滑動驗證碼基本設計原理
  • 如何封裝一款可擴展的滑動驗證碼組件
  • 如何使用 dumi 搭建組件文檔
  • 如何發布自己第一個npm組件包

如果你對以上任意知識點感興趣,相信這篇文章都會給你帶來啟發。

效果演示

圖片

滑動驗證組件基本使用和技術實現

上圖是實現的滑動驗證組件的一個效果演示,當然還有很多配置項可以選擇,以便支持更多 定制化 的場景。接下來我先介紹一下如何安裝和使用這款驗證碼插件,讓大家有一個直觀的體驗,然后我會詳細介紹一下滑動驗證碼的實現思路,如果大家有一定的技術基礎,也可以直接跳到技術實現部分。

基本使用

因為 react-slider-vertify 這款組件我已經發布到 npm 上了,所以大家可以按照如下方式安裝和使用:

1.安裝

  1. # 或者 yarn add @alex_xu/react-slider-vertify 
  2. npm i @alex_xu/react-slider-vertify -S 

2.使用

  1. import React from 'react'
  2. import { Vertify } from '@alex_xu/react-slider-vertify'
  3.  
  4. export default () => { 
  5.     return <Vertify  
  6.             width={320} 
  7.             height={160} 
  8.             onSuccess={() => alert('success')}  
  9.             onFail={() => alert('fail')}  
  10.             onRefresh={() => alert('refresh')}  
  11.         /> 
  12. }; 

通過以上兩步我們就可以輕松使用這款滑動驗證碼組件了,是不是很簡單?

當然我也暴露了很多可配置的屬性,讓大家對組件有更好的控制。參考如下:

技術實現

在做這個項目之前我也研究了一些滑動驗證碼的知識以及已有的技術方案,收獲很多。接下來我會以我的組件設計思路來和大家介紹如何用 react 來實現和封裝滑動驗證碼組件,如果大家有更好的想法和建議, 也可以在評論區隨時和我反饋。

1.組件設計的思路和技巧

每個人都有自己設計組件的方式和風格,但最終目的都是更 優雅 的設計組件。這里我大致列舉一下 優雅 組件的設計指標:

  • 可讀性(代碼格式統一清晰,注釋完整,代碼結構層次分明,編程范式使用得當)
  • 可用性(代碼功能完整,在不同場景都能很好兼容,業務邏輯覆蓋率)
  • 復用性(代碼可以很好的被其他業務模塊復用)
  • 可維護性(代碼易于維護和擴展,并有一定的向下/向上兼容性)
  • 高性能

以上是我自己設計組件的考量指標,大家可以參考一下。

另外設計組件之前我們還需要明確需求,就拿滑動驗證碼組件舉例,我們需要先知道它的使用場景(用于登錄注冊、活動、論壇、短信等高風險業務場景的人機驗證服務)和需求(交互邏輯,以什么樣的方式驗證,需要暴露哪些屬性)。

以上就是我梳理的一個大致的組件開發需求,在開發具體組件之前,如果遇到復雜的業務邏輯,我們還可以將每一個實現步驟列舉出來,然后一一實現,這樣有助于整理我們的思路和更高效的開發。

2.滑動驗證碼基本實現原理

在介紹完組件設計思路和需求分析之后,我們來看看滑動驗證碼的實現原理。

我們都知道設計驗證碼的主要目的是為了防止機器非法暴力地入侵我們的應用,其中核心要解決的問題就是判斷應用是誰在操作(人 or 機器),所以通常的解決方案就是隨機識別。

上圖我們可以看到只有用戶手動將滑塊拖拽到對應的鏤空區域,才算驗證成功,鏤空區域的位置是隨機的(隨機性測試這里暫時以前端的方式來實現,更安全的做法是通過后端來返回位置和圖片)。

基于以上分析我們就可以得出一個基本的滑動驗證碼設計原理圖:

接下來我們就一起封裝這款可擴展的滑動驗證碼組件。

3.封裝一款可擴展的滑動驗證碼組件

按照我開發組件一貫的風格,我會先基于需求來編寫組件的基本框架:

  1. import React, { useRef, useState, useEffect, ReactNode } from 'react'
  2.  
  3. interface IVertifyProp { 
  4.     /** 
  5.      * @description   canvas寬度   
  6.      * @default       320 
  7.      */ 
  8.     width:number,  
  9.     /** 
  10.      * @description   canvas高度   
  11.      * @default       160 
  12.      */ 
  13.     height:number,  
  14.     /** 
  15.      * @description   滑塊邊長   
  16.      * @default       42 
  17.      */ 
  18.      l:number, 
  19.      /** 
  20.      * @description   滑塊半徑  
  21.      * @default       9 
  22.      */ 
  23.       r:number, 
  24.      /** 
  25.      * @description   是否可見 
  26.      * @default       true 
  27.      */ 
  28.       visible:boolean, 
  29.      /** 
  30.      * @description   滑塊文本 
  31.      * @default       向右滑動填充拼圖 
  32.      */ 
  33.       text:string | ReactNode, 
  34.       /** 
  35.      * @description   刷新按鈕icon, 為icon的url地址 
  36.      * @default       - 
  37.      */ 
  38.        refreshIcon:string, 
  39.      /** 
  40.      * @description   用于獲取隨機圖片的url地址 
  41.      * @default       https://picsum.photos/${id}/${width}/${height}, 具體參考https://picsum.photos/, 只需要實現類似接口即可 
  42.      */ 
  43.        imgUrl:string, 
  44.     /** 
  45.      * @description   驗證成功回調   
  46.      * @default       ():void => {} 
  47.      */ 
  48.     onSuccess:VoidFunction,  
  49.     /** 
  50.      * @description   驗證失敗回調   
  51.      * @default       ():void => {} 
  52.      */ 
  53.     onFail:VoidFunction,  
  54.     /** 
  55.      * @description   刷新時回調   
  56.      * @default       ():void => {} 
  57.      */ 
  58.     onRefresh:VoidFunction 
  59.  
  60. export default ({  
  61.     width = 320, 
  62.     height = 160, 
  63.     l = 42, 
  64.     r = 9, 
  65.     imgUrl, 
  66.     text, 
  67.     refreshIcon = 'http://yourimgsite/icon.png'
  68.     visible = true
  69.     onSuccess, 
  70.     onFail, 
  71.     onRefresh 
  72.  }: IVertifyProp) => { 
  73.      return <div className="vertifyWrap"
  74.         <div className="canvasArea"
  75.             <canvas width={width} height={height}></canvas> 
  76.             <canvas className="block" width={width} height={height}></canvas> 
  77.         </div> 
  78.         <div className={sliderClass}> 
  79.             <div className="sliderMask"
  80.                 <div className="slider"
  81.                     <div className="sliderIcon">&rarr;</div> 
  82.                 </div> 
  83.             </div> 
  84.             <div className="sliderText">{ textTip }</div> 
  85.         </div> 
  86.         <div className="refreshIcon" onClick={handleRefresh}></div> 
  87.         <div className="loadingContainer"
  88.             <div className="loadingIcon"></div> 
  89.             <span>加載中...</span> 
  90.         </div> 
  91.     </div> 
  92.  } 

以上就是我們組件的基本框架結構。從代碼中可以發現組件屬性一目了然,這都是提前做好需求整理帶來的好處,它可以讓我們在編寫組件時思路更清晰。在編寫好基本的 css 樣式之后我們看到的界面是這樣的:

接下來我們需要實現以下幾個核心功能:

  • 鏤空效果的 canvas 圖片實現
  • 鏤空圖案 canvas 實現
  • 滑塊移動和驗證邏輯實現

上面的描述可能比較抽象,我畫張圖示意一下:

因為組件實現完全采用的 react hooks ,如果大家對 hooks 不熟悉也可以參考我之前的文章:

10分鐘教你手寫8個常用的自定義hooks

一.實現鏤空效果的 canvas 圖片

在開始 coding 之前我們需要對 canvas 有個基本的了解,建議不熟悉的朋友可以參考高效 canvas 學習文檔: Canvas of MDN。

由上圖可知首先要解決的問題就是如何用 canvas 畫不規則的圖形,這里我簡單的畫個草圖:

我們只需要使用 canvas 提供的 路徑api 畫出上圖的路徑,并將路徑填充為任意半透明的顏色即可。建議大家不熟悉的可以先了解如下 api :

  • beginPath() 開始路徑繪制
  • moveTo() 移動筆觸到指定點
  • arc() 繪制弧形
  • lineTo() 畫線
  • stroke() 描邊
  • fill() 填充
  • clip() 裁切路徑

實現方法如下:

  1. const drawPath  = (ctx:any, x:number, y:number, operation: 'fill' | 'clip') => { 
  2.     ctx.beginPath() 
  3.     ctx.moveTo(x, y) 
  4.     ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI) 
  5.     ctx.lineTo(x + l, y) 
  6.     ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI) 
  7.     ctx.lineTo(x + l, y + l) 
  8.     ctx.lineTo(x, y + l) 
  9.     // anticlockwise為一個布爾值。為true時,是逆時針方向,否則順時針方向 
  10.     ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true
  11.     ctx.lineTo(x, y) 
  12.     ctx.lineWidth = 2 
  13.     ctx.fillStyle = 'rgba(255, 255, 255, 0.8)' 
  14.     ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)' 
  15.     ctx.stroke() 
  16.     ctx.globalCompositeOperation = 'destination-over' 
  17.     // 判斷是填充還是裁切, 裁切主要用于生成圖案滑塊 
  18.     operation === 'fill'? ctx.fill() : ctx.clip() 

這塊實現方案也是參考了 yield 大佬的原生 js 實現,這里需要補充的一點是 canvas 的 globalCompositeOperation 屬性,它的主要目的是設置如何將一個源(新的)圖像繪制到目標(已有)的圖像上。

  • 源圖像 = 我們打算放置到畫布上的繪圖
  • 目標圖像 = 我們已經放置在畫布上的繪圖

w3c上有個形象的例子:

這里之所以設置該屬性是為了讓鏤空的形狀不受背景底圖的影響并覆蓋在背景底圖的上方。如下:

接下來我們只需要將圖片繪制到畫布上即可:

  1. const canvasCtx = canvasRef.current.getContext('2d'
  2. // 繪制鏤空形狀 
  3. drawPath(canvasCtx, 50, 50, 'fill'
  4.  
  5. // 畫入圖片 
  6. canvasCtx.drawImage(img, 0, 0, width, height) 

當然至于如何生成隨機圖片和隨機位置,實現方式也很簡單,前端實現的話采用 Math.random 即可。

二.實現鏤空圖案 canvas

上面實現了鏤空形狀,那么鏤空圖案也類似,我們只需要使用 clip() 方法將圖片裁切到形狀遮罩里,并將鏤空圖案置于畫布左邊即可。代碼如下:

  1. const blockCtx = blockRef.current.getContext('2d'
  2. drawPath(blockCtx, 50, 50, 'clip'
  3. blockCtx.drawImage(img, 0, 0, width, height) 
  4.  
  5. // 提取圖案滑塊并放到最左邊 
  6. const y1 = 50 - r * 2 - 1 
  7. const ImageData = blockCtx.getImageData(xRef.current - 3, y1, L, L) 
  8. // 調整滑塊畫布寬度 
  9. blockRef.current.width = L 
  10. blockCtx.putImageData(ImageData, 0, y1) 

上面的代碼我們用到了 getImageData 和 putImageData,這兩個 api 主要用來獲取 canvas 畫布場景像素數據和對場景進行像素數據的寫入。實現后 的效果如下:

三.實現滑塊移動和驗證邏輯

實現滑塊移動的方案也比較簡單,我們只需要利用鼠標的 event 事件即可:

  • onMouseDown
  • onMouseMove
  • onMouseUp

以上是一個簡單的示意圖,具體實現代碼如下:

  1. const handleDragMove = (e) => { 
  2.     if (!isMouseDownRef.currentreturn false 
  3.     e.preventDefault() 
  4.     // 為了支持移動端, 可以使用e.touches[0] 
  5.     const eventX = e.clientX || e.touches[0].clientX 
  6.     const eventY = e.clientY || e.touches[0].clientY 
  7.     const moveX = eventX - originXRef.current 
  8.     const moveY = eventY - originYRef.current 
  9.     if (moveX < 0 || moveX + 36 >= width) return false 
  10.     setSliderLeft(moveX) 
  11.     const blockLeft = (width - l - 2r) / (width - l) * moveX 
  12.     blockRef.current.style.left = blockLeft + 'px' 

當然我們還需要對拖拽停止后的事件做監聽,來判斷是否驗證成功,并埋入成功和失敗的回調。代碼如下:

  1. const handleDragEnd = (e) => { 
  2.     if (!isMouseDownRef.currentreturn false 
  3.     isMouseDownRef.current = false 
  4.     const eventX = e.clientX || e.changedTouches[0].clientX 
  5.     if (eventX === originXRef.currentreturn false 
  6.     setSliderClass('sliderContainer'
  7.     const { flag, result } = verify() 
  8.     if (flag) { 
  9.       if (result) { 
  10.         setSliderClass('sliderContainer sliderContainer_success'
  11.         // 成功后的自定義回調函數 
  12.         typeof onSuccess === 'function' && onSuccess() 
  13.       } else { 
  14.         // 驗證失敗, 刷新重置 
  15.         setSliderClass('sliderContainer sliderContainer_fail'
  16.         setTextTip('請再試一次')  
  17.         reset() 
  18.       } 
  19.     } else { 
  20.       setSliderClass('sliderContainer sliderContainer_fail'
  21.       // 失敗后的自定義回調函數 
  22.       typeof onFail === 'function' && onFail() 
  23.       setTimeout(reset.bind(this), 1000) 
  24.     } 

實現后的效果如下:

[[425875]]

當然還有一些細節需要優化處理,這里在 github 上有完整的代碼,大家可以參考學習一下,如果大家想對該組件參與貢獻,也可以隨時提 issue。

四.如何使用 dumi 搭建組件文檔

為了讓組件能被其他人更好的理解和使用,我們可以搭建組件文檔。作為一名熱愛開源的前端 coder,編寫組件文檔也是個很好的開發習慣。接下來我們也為 react-slider-vertify 編寫一下組件文檔,這里我使用 dumi 來搭建組件文檔,當然大家也可以用其他方案(比如storybook)。我們先看一下搭建后的效果:

dumi 搭建組件文檔非常簡單,接下來和大家介紹一下安裝使用方式。

1.安裝

  1. $ npx @umijs/create-dumi-lib        # 初始化一個文檔模式的組件庫開發腳手架 
  2. or 
  3. $ yarn create @umijs/dumi-lib 
  4.  
  5. $ npx @umijs/create-dumi-lib --site # 初始化一個站點模式的組件庫開發腳手架 
  6. or 
  7. $ yarn create @umijs/dumi-lib --site 

2.本地運行

  1. npm run dev 
  2. or 
  3. yarn dev 

3.編寫文檔

dumi 約定式的定義了文檔編寫的位置和方式,其官網上也有具體的飯介紹,這里簡單給大家上一個 dumi 搭建的組件目錄結構圖:

 

 

我們可以在 docs 下編寫組件庫文檔首頁和引導頁的說明,在單個組件的文件夾下使用 index.md 來編寫組件自身的使用文檔,當然整個過程非常簡單,我這里舉一個文檔的例子:

通過這種方式 dumi 就可以幫我們自動渲染一個組件使用文檔。如果大家想學習更多組件文檔搭建的內容,也可以在 dumi 官網學習。

五.發布自己第一個npm組件包

最后一個問題就是組件發布。之前很多朋友問我如何將自己的組件發布到 npm 上讓更多人使用,這塊的知識網上有很多資料可以學習,那今天就以滑動驗證碼 @alex_xu/react-slider-vertify 的例子,來和大家做一個簡單的介紹。

1.擁有一個 npm 賬號并登錄

如果大家之前沒有 npm 賬號,可以在 npm 官網 注冊一個,然后用我們熟悉的 IDE 終端登錄一次:

  1. npm login 

跟著提示輸入完用戶名密碼之后我們就能通過命令行發布組件包了:

  1. npm publish --access public 

之所以指令后面會加 public 參數,是為了避免權限問題導致組件包無法發布成功。我們為了省事也可以把發布命令配置到 package.json 中,在組件打包完成后自動發布:

  1.     "scripts": { 
  2.         "start""dumi dev"
  3.         "release""npm run build && npm publish --access public"
  4.   } 

這樣我們就能將組件輕松發布到 npm 上供他人使用啦! 我之前也開源了很多組件庫,如果大家對組件打包細節和構建流程有疑問,也可以參考我之前開源項目的方案。發布到 npm 后的效果:

本文轉載自微信公眾號「趣談前端」

 

責任編輯:姜華 來源: 趣談前端
相關推薦

2023-12-08 08:02:40

開箱React?組件

2018-01-17 15:05:22

框架設計爬蟲Scrapy

2022-07-14 11:31:04

SQLToolsVScode數據庫

2021-09-26 05:00:11

Vscode插件

2021-08-26 05:15:22

圖片編輯器 H5-DooringMitu-Doorin

2022-08-31 08:32:22

數據可視化項目nocode

2021-09-11 21:03:09

可視化搭建框架

2013-11-28 15:02:34

Ubuntu技巧Geary

2023-12-12 13:50:00

代碼業務狀態

2022-04-18 19:02:53

chrome擴展瀏覽器

2021-09-14 08:38:57

組件開源前端

2019-11-26 08:43:44

平臺桌面軟件

2024-01-11 08:19:17

開源界驗證碼滑動類

2022-01-24 11:02:27

PySimpleGUPython計算器

2015-03-17 09:28:04

2016-11-14 15:40:01

Android

2022-05-27 10:00:06

C++游戲引擎

2023-06-27 16:42:18

Tinygrad深度學習工具

2011-06-17 11:22:33

jQueryjQuery插件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九色九九 | 免费一区 | 男女激情网站免费 | 国产精品成人一区二区三区 | 99re视频在线 | 在线免费观看视频黄 | 欧区一欧区二欧区三免费 | 欧美福利久久 | 影音先锋中文字幕在线观看 | 成人99| 亚洲美乳中文字幕 | 日韩免费高清视频 | 国产成人亚洲精品自产在线 | 久久黄色精品视频 | 久久伊人影院 | 欧美精品中文字幕久久二区 | 日日噜噜噜夜夜爽爽狠狠视频97 | 人人爽人人草 | 国产免费一区二区三区网站免费 | 精品久久久久久亚洲精品 | 欧美极品在线观看 | 国产精品久久一区 | 国产视频一视频二 | 中文字幕精品一区二区三区精品 | 一区二区在线 | 欧美一区二区三区在线视频 | 天天舔天天 | h片免费看 | 国产精品免费av | 日本高清不卡视频 | 青青草社区| 色频 | 久久高清| 国色天香成人网 | 欧美精品一区二区在线观看 | 成人国产精品久久久 | 九九精品在线 | 91在线精品一区二区 | 国产999精品久久久 精品三级在线观看 | 欧美一区二区视频 | 九九国产|