最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端實(shí)現(xiàn)電子簽名(web、移動(dòng)端)通用的實(shí)戰(zhàn)過(guò)程

 更新時(shí)間:2022年12月12日 10:11:02   作者:桃小瑞  
電子簽名通俗來(lái)說(shuō)就是通過(guò)技術(shù)手段實(shí)現(xiàn)在電子文檔上加載電子形式的簽名,下面這篇文章主要給大家介紹了關(guān)于前端實(shí)現(xiàn)電子簽名(web、移動(dòng)端)通用的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在現(xiàn)在的時(shí)代發(fā)展中,從以前的手寫(xiě)簽名,逐漸衍生出了電子簽名。電子簽名和紙質(zhì)手寫(xiě)簽名一樣具有法律效應(yīng)。電子簽名目前主要還是在需要個(gè)人確認(rèn)的產(chǎn)品環(huán)節(jié)和司法類相關(guān)的產(chǎn)品上較多。

舉個(gè)常用的例子,大家都用過(guò)釘釘,釘釘上面就有電子簽名,相信大家這肯定是知道的。

那作為前端的我們?nèi)绾螌?shí)現(xiàn)電子簽名呢?其實(shí)在html5中已經(jīng)出現(xiàn)了一個(gè)重要級(jí)別的輔助標(biāo)簽,是啥呢?那就是canvas

什么是canvas

Canvas(畫(huà)布)是在HTML5中新增的標(biāo)簽用于在網(wǎng)頁(yè)實(shí)時(shí)生成圖像,并且可以操作圖像內(nèi)容,基本上它是一個(gè)可以用JavaScript操作的位圖(bitmap)。Canvas 對(duì)象表示一個(gè) HTML 畫(huà)布元素 -。它沒(méi)有自己的行為,但是定義了一個(gè) API 支持腳本化客戶端繪圖操作。

大白話就是canvas是一個(gè)可以在上面通過(guò)javaScript畫(huà)圖的標(biāo)簽,通過(guò)其提供的context(上下文)Api進(jìn)行繪制,在這個(gè)過(guò)程中canvas充當(dāng)畫(huà)布的角色。

<canvas></canvas>

如何使用

canvas給我們提供了很多的Api,供我們使用,我們只需要在body標(biāo)簽中創(chuàng)建一個(gè)canvas標(biāo)簽,在script標(biāo)簽中拿到canvas這個(gè)標(biāo)簽的節(jié)點(diǎn),并創(chuàng)建context(上下文)就可以使用了。

...
<body>
    <canvas></canvas>
</body>
<script>
    // 獲取canvas 實(shí)例
    const canvas = document.querySelector('canvas')
    canvas.getContext('2d')
</script>
...

步入正題。

實(shí)現(xiàn)電子簽名

知道幾何的朋友都很清楚,線有點(diǎn)繪成,面由線繪成。

多點(diǎn)成線,多線成面。

所以我們實(shí)際只需要拿到當(dāng)前觸摸的坐標(biāo)點(diǎn),進(jìn)行成線處理就可以了。

在body中添加canvas標(biāo)簽

在這里我們不僅需要在在body中添加canvas標(biāo)簽,我們還需要添加兩個(gè)按鈕,分別是取消保存(后面我們會(huì)用到)。

<body>
    <canvas></canvas>
    <div>
        <button>取消</button>
        <button>保存</button>
    </div>
</body>

添加文件

我這里全程使用js進(jìn)行樣式設(shè)置及添加。

// 配置內(nèi)容
    const config = {
        width: 400, // 寬度
        height: 200, // 高度
        lineWidth: 5, // 線寬
        strokeStyle: 'red', // 線條顏色
        lineCap: 'round', // 設(shè)置線條兩端圓角
        lineJoin: 'round', // 線條交匯處圓角
    }

獲取canvas實(shí)例

這里我們使用querySelector獲取canvas的dom實(shí)例,并設(shè)置樣式和創(chuàng)建上下文。

    // 獲取canvas 實(shí)例
    const canvas = document.querySelector('canvas')
    // 設(shè)置寬高
    canvas.width = config.width
    canvas.height = config.height
    // 設(shè)置一個(gè)邊框,方便我們查看及使用
    canvas.style.border = '1px solid #000'
    // 創(chuàng)建上下文
    const ctx = canvas.getContext('2d')

基礎(chǔ)設(shè)置

我們將canvas的填充色為透明,并繪制填充一個(gè)矩形,作為我們的畫(huà)布,如果不設(shè)置這個(gè)填充背景色,在我們初識(shí)渲染的時(shí)候是一個(gè)黑色背景,這也是它的一個(gè)默認(rèn)色。

    // 設(shè)置填充背景色
    ctx.fillStyle = 'transparent'
    // 繪制填充矩形
    ctx.fillRect(
        0, // x 軸起始繪制位置
        0, // y 軸起始繪制位置
        config.width, // 寬度
        config.height // 高度
    );

上次繪制路徑保存

這里我們需要聲明一個(gè)對(duì)象,用來(lái)記錄我們上一次繪制的路徑結(jié)束坐標(biāo)點(diǎn)及偏移量。

  • 保存上次坐標(biāo)點(diǎn)這個(gè)我不用說(shuō)大家都懂;
  • 為啥需要保存偏移量呢,因?yàn)槭髽?biāo)和畫(huà)布上的距離是存在一定的偏移距離,在我們繪制的過(guò)程中需要減去這個(gè)偏移量,才是我們實(shí)際的繪制坐標(biāo)。
  • 但我發(fā)現(xiàn)chrome中不需要減去這個(gè)偏移量,拿到的就是實(shí)際的坐標(biāo),之前在微信小程序中使用就需要減去偏移量,需要在小程序中使用的朋友需要注意這一點(diǎn)哦。
    // 保存上次繪制的 坐標(biāo)及偏移量
    const client = {
        offsetX: 0, // 偏移量
        offsetY: 0,
        endX: 0, // 坐標(biāo)
        endY: 0
    }

設(shè)備兼容

我們需要它不僅可以在web端使用,還需要在移動(dòng)端使用,我們需要給它做設(shè)備兼容處理。我們通過(guò)調(diào)用navigator.userAgent獲取當(dāng)前設(shè)備信息,進(jìn)行正則匹配判斷。

    // 判斷是否為移動(dòng)端
    const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))

初始化

這里我們?cè)诒O(jiān)聽(tīng)鼠標(biāo)按下(mousedown)(web端)/觸摸開(kāi)始(touchstart)的時(shí)候進(jìn)行初始化,事件監(jiān)聽(tīng)采用addEventListener。

    // 創(chuàng)建鼠標(biāo)/手勢(shì)按下監(jiān)聽(tīng)器
    window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)

三元判斷說(shuō)明: 這里當(dāng)mobileStatustrue時(shí)則表示為移動(dòng)端,反之則為web端,后續(xù)使用到的三元依舊是這個(gè)意思。

聲明初始化方法

我們添加一個(gè)init方法作為監(jiān)聽(tīng)鼠標(biāo)按下/觸摸開(kāi)始的回調(diào)方法。

這里我們需要獲取到當(dāng)前鼠標(biāo)按下/觸摸開(kāi)始的偏移量和坐標(biāo),進(jìn)行起始點(diǎn)繪制。

Tips:web端可以直接通過(guò)event中取到,而移動(dòng)端則需要在event.changedTouches[0]中取到。

這里我們?cè)诔跏蓟笤俦O(jiān)聽(tīng)鼠標(biāo)的移動(dòng)。

    // 初始化
    const init = event => {
        // 獲取偏移量及坐標(biāo)
        const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event 

        // 修改上次的偏移量及坐標(biāo)
        client.offsetX = offsetX
        client.offsetY = offsetY
        client.endX = pageX
        client.endY = pageY

        // 清除以上一次 beginPath 之后的所有路徑,進(jìn)行繪制
        ctx.beginPath()

        // 根據(jù)配置文件設(shè)置進(jìn)行相應(yīng)配置
        ctx.lineWidth = config.lineWidth
        ctx.strokeStyle = config.strokeStyle
        ctx.lineCap = config.lineCap
        ctx.lineJoin = config.lineJoin

        // 設(shè)置畫(huà)線起始點(diǎn)位
        ctx.moveTo(client.endX, client.endY)

        // 監(jiān)聽(tīng) 鼠標(biāo)移動(dòng)或手勢(shì)移動(dòng)
        window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
    }

繪制

這里我們添加繪制draw方法,作為監(jiān)聽(tīng)鼠標(biāo)移動(dòng)/觸摸移動(dòng)的回調(diào)方法。

    // 繪制
    const draw = event => {
        // 獲取當(dāng)前坐標(biāo)點(diǎn)位
        const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
        // 修改最后一次繪制的坐標(biāo)點(diǎn)
        client.endX = pageX
        client.endY = pageY

        // 根據(jù)坐標(biāo)點(diǎn)位移動(dòng)添加線條
        ctx.lineTo(pageX , pageY )

        // 繪制
        ctx.stroke()
    }

結(jié)束繪制

添加了監(jiān)聽(tīng)鼠標(biāo)移動(dòng)/觸摸移動(dòng)我們一定要記得取消監(jiān)聽(tīng)并結(jié)束繪制,不然的話它會(huì)一直監(jiān)聽(tīng)并繪制的。

這里我們創(chuàng)建一個(gè)cloaseDraw方法作為鼠標(biāo)彈起/結(jié)束觸摸的回調(diào)方法來(lái)結(jié)束繪制并移除鼠標(biāo)移動(dòng)/觸摸移動(dòng)的監(jiān)聽(tīng)。

canvas結(jié)束繪制則需要調(diào)用closePath()讓其結(jié)束繪制

    // 結(jié)束繪制
    const cloaseDraw = () => {
        // 結(jié)束繪制
        ctx.closePath()
        // 移除鼠標(biāo)移動(dòng)或手勢(shì)移動(dòng)監(jiān)聽(tīng)器
        window.removeEventListener("mousemove", draw)
    }

添加結(jié)束回調(diào)監(jiān)聽(tīng)器

    // 創(chuàng)建鼠標(biāo)/手勢(shì) 彈起/離開(kāi) 監(jiān)聽(tīng)器
    window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw)

ok,現(xiàn)在我們的電子簽名功能還差一丟丟可以實(shí)現(xiàn)完了,現(xiàn)在已經(jīng)可以正常的簽名了。

我們來(lái)看一下效果:

取消功能/清空畫(huà)布

我們?cè)趧傞_(kāi)始創(chuàng)建的那兩個(gè)按鈕開(kāi)始排上用場(chǎng)了。

這里我們創(chuàng)建一個(gè)cancel的方法作為取消并清空畫(huà)布使用

    // 取消-清空畫(huà)布
    const cancel = () => {
        // 清空當(dāng)前畫(huà)布上的所有繪制內(nèi)容
        ctx.clearRect(0, 0, config.width, config.height)
    }

然后我們將這個(gè)方法和取消按鈕進(jìn)行綁定

     <button onclick="cancel()">取消</button>

保存功能

這里我們創(chuàng)建一個(gè)save的方法作為保存畫(huà)布上的內(nèi)容使用。

將畫(huà)布上的內(nèi)容保存為圖片/文件的方法有很多,比較常見(jiàn)的是blobtoDataURL這兩種方案,但toDataURL這哥們沒(méi)blob強(qiáng),適配也不咋滴。所以我們這里采用a標(biāo)簽 ? blob方案實(shí)現(xiàn)圖片的保存下載。

    // 保存-將畫(huà)布內(nèi)容保存為圖片
    const save = () => {
        // 將canvas上的內(nèi)容轉(zhuǎn)成blob流
        canvas.toBlob(blob => {
            // 獲取當(dāng)前時(shí)間并轉(zhuǎn)成字符串,用來(lái)當(dāng)做文件名
            const date = Date.now().toString()
            // 創(chuàng)建一個(gè) a 標(biāo)簽
            const a = document.createElement('a')
            // 設(shè)置 a 標(biāo)簽的下載文件名
            a.download = `${date}.png`
            // 設(shè)置 a 標(biāo)簽的跳轉(zhuǎn)路徑為 文件流地址
            a.href = URL.createObjectURL(blob)
            // 手動(dòng)觸發(fā) a 標(biāo)簽的點(diǎn)擊事件
            a.click()
            // 移除 a 標(biāo)簽
            a.remove()
        })
    }

然后我們將這個(gè)方法和保存按鈕進(jìn)行綁定

    <button onclick="save()">保存</button>

我們將剛剛繪制的內(nèi)容進(jìn)行保存,點(diǎn)擊保存按鈕,就會(huì)進(jìn)行下載保存

完整代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <canvas></canvas>
    <div>
        <button onclick="cancel()">取消</button>
        <button onclick="save()">保存</button>
    </div>
</body>
<script>
    // 配置內(nèi)容
    const config = {
        width: 400, // 寬度
        height: 200, // 高度
        lineWidth: 5, // 線寬
        strokeStyle: 'red', // 線條顏色
        lineCap: 'round', // 設(shè)置線條兩端圓角
        lineJoin: 'round', // 線條交匯處圓角
    }

    // 獲取canvas 實(shí)例
    const canvas = document.querySelector('canvas')
    // 設(shè)置寬高
    canvas.width = config.width
    canvas.height = config.height
    // 設(shè)置一個(gè)邊框
    canvas.style.border = '1px solid #000'
    // 創(chuàng)建上下文
    const ctx = canvas.getContext('2d')

    // 設(shè)置填充背景色
    ctx.fillStyle = 'transparent'
    // 繪制填充矩形
    ctx.fillRect(
        0, // x 軸起始繪制位置
        0, // y 軸起始繪制位置
        config.width, // 寬度
        config.height // 高度
    );

    // 保存上次繪制的 坐標(biāo)及偏移量
    const client = {
        offsetX: 0, // 偏移量
        offsetY: 0,
        endX: 0, // 坐標(biāo)
        endY: 0
    }

    // 判斷是否為移動(dòng)端
    const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))

    // 初始化
    const init = event => {
        // 獲取偏移量及坐標(biāo)
        const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event 

        // 修改上次的偏移量及坐標(biāo)
        client.offsetX = offsetX
        client.offsetY = offsetY
        client.endX = pageX
        client.endY = pageY

        // 清除以上一次 beginPath 之后的所有路徑,進(jìn)行繪制
        ctx.beginPath()
        // 根據(jù)配置文件設(shè)置相應(yīng)配置
        ctx.lineWidth = config.lineWidth
        ctx.strokeStyle = config.strokeStyle
        ctx.lineCap = config.lineCap
        ctx.lineJoin = config.lineJoin
        // 設(shè)置畫(huà)線起始點(diǎn)位
        ctx.moveTo(client.endX, client.endY)
        // 監(jiān)聽(tīng) 鼠標(biāo)移動(dòng)或手勢(shì)移動(dòng)
        window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
    }
    // 繪制
    const draw = event => {
        // 獲取當(dāng)前坐標(biāo)點(diǎn)位
        const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
        // 修改最后一次繪制的坐標(biāo)點(diǎn)
        client.endX = pageX
        client.endY = pageY

        // 根據(jù)坐標(biāo)點(diǎn)位移動(dòng)添加線條
        ctx.lineTo(pageX , pageY )

        // 繪制
        ctx.stroke()
    }
    // 結(jié)束繪制
    const cloaseDraw = () => {
        // 結(jié)束繪制
        ctx.closePath()
        // 移除鼠標(biāo)移動(dòng)或手勢(shì)移動(dòng)監(jiān)聽(tīng)器
        window.removeEventListener("mousemove", draw)
    }
    // 創(chuàng)建鼠標(biāo)/手勢(shì)按下監(jiān)聽(tīng)器
    window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
    // 創(chuàng)建鼠標(biāo)/手勢(shì) 彈起/離開(kāi) 監(jiān)聽(tīng)器
    window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw)
    
    // 取消-清空畫(huà)布
    const cancel = () => {
        // 清空當(dāng)前畫(huà)布上的所有繪制內(nèi)容
        ctx.clearRect(0, 0, config.width, config.height)
    }
    // 保存-將畫(huà)布內(nèi)容保存為圖片
    const save = () => {
        // 將canvas上的內(nèi)容轉(zhuǎn)成blob流
        canvas.toBlob(blob => {
            // 獲取當(dāng)前時(shí)間并轉(zhuǎn)成字符串,用來(lái)當(dāng)做文件名
            const date = Date.now().toString()
            // 創(chuàng)建一個(gè) a 標(biāo)簽
            const a = document.createElement('a')
            // 設(shè)置 a 標(biāo)簽的下載文件名
            a.download = `${date}.png`
            // 設(shè)置 a 標(biāo)簽的跳轉(zhuǎn)路徑為 文件流地址
            a.href = URL.createObjectURL(blob)
            // 手動(dòng)觸發(fā) a 標(biāo)簽的點(diǎn)擊事件
            a.click()
            // 移除 a 標(biāo)簽
            a.remove()
        })
    }
</script>
</html>

各內(nèi)核和瀏覽器支持情況

Mozilla 程序從 Gecko 1.8 (Firefox 1.5 (en-US)) 開(kāi)始支持 <canvas>。它首先是由 Apple 引入的,用于 OS X Dashboard 和 Safari。Internet Explorer 從 IE9 開(kāi)始支持<canvas> ,更舊版本的 IE 中,頁(yè)面可以通過(guò)引入 Google 的 Explorer Canvas 項(xiàng)目中的腳本來(lái)獲得<canvas>支持。Google Chrome 和 Opera 9+ 也支持 <canvas>

小程序中提示

在小程序中我們?nèi)绻柩綄?shí)現(xiàn)的話,也是同樣的原理哦,只是我們需要將創(chuàng)建實(shí)例和上下文的Api進(jìn)行修改,因?yàn)樾〕绦蛑惺菦](méi)有dom,既然沒(méi)有dom,哪來(lái)的操作dom這個(gè)操作呢。

總結(jié)

到此這篇關(guān)于前端實(shí)現(xiàn)電子簽名(web、移動(dòng)端)通用的文章就介紹到這了,更多相關(guān)前端實(shí)現(xiàn)通用電子簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MockJs結(jié)合json-server模擬后臺(tái)數(shù)據(jù)

    MockJs結(jié)合json-server模擬后臺(tái)數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了MockJs結(jié)合json-server模擬后臺(tái)數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Js圖片點(diǎn)擊切換輪播實(shí)現(xiàn)代碼

    Js圖片點(diǎn)擊切換輪播實(shí)現(xiàn)代碼

    這篇文章主要介紹了Js圖片點(diǎn)擊切換輪播實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • JavaScript獲取網(wǎng)頁(yè)支持表單字符集的方法

    JavaScript獲取網(wǎng)頁(yè)支持表單字符集的方法

    這篇文章主要介紹了JavaScript獲取網(wǎng)頁(yè)支持表單字符集的方法,涉及javascript中acceptCharset方法的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • JavaScript腳本延遲加載有哪些方式

    JavaScript腳本延遲加載有哪些方式

    本文主要介紹了JavaScript腳本延遲加載有哪些方式,主要介紹了五種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • 輕松實(shí)現(xiàn)javascript數(shù)據(jù)雙向綁定

    輕松實(shí)現(xiàn)javascript數(shù)據(jù)雙向綁定

    這篇文章教大家輕松實(shí)現(xiàn)javascript數(shù)據(jù)雙向綁定,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-11-11
  • JavaScript選擇排序算法原理與實(shí)現(xiàn)方法示例

    JavaScript選擇排序算法原理與實(shí)現(xiàn)方法示例

    這篇文章主要介紹了JavaScript選擇排序算法原理與實(shí)現(xiàn)方法,簡(jiǎn)單分析了選擇排序算法的概念、原理并結(jié)合實(shí)例形式分析了JavaScript選擇排序算法的相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2018-08-08
  • layui 地區(qū)三級(jí)聯(lián)動(dòng) form select 渲染的實(shí)例

    layui 地區(qū)三級(jí)聯(lián)動(dòng) form select 渲染的實(shí)例

    今天小編就為大家分享一篇layui 地區(qū)三級(jí)聯(lián)動(dòng) form select 渲染的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09
  • webpack-loader的使用詳解

    webpack-loader的使用詳解

    webpack默認(rèn)只能處理js其他的像css,圖片都需要借助loader來(lái)處理,這篇文章主要介紹了webpack-loader的使用詳解,需要的朋友可以參考下
    2024-04-04
  • JS實(shí)現(xiàn)數(shù)組刪除指定元素功能示例

    JS實(shí)現(xiàn)數(shù)組刪除指定元素功能示例

    這篇文章主要介紹了JS實(shí)現(xiàn)數(shù)組刪除指定元素功能,涉及javascript數(shù)組遍歷、排序、判斷等相關(guān)操作技巧,需要的朋友可以參考下
    2019-06-06
  • 簡(jiǎn)單易懂的天氣插件(代碼分享)

    簡(jiǎn)單易懂的天氣插件(代碼分享)

    本文主要分享了天氣插件的示例代碼。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02

最新評(píng)論

阿坝县| 清丰县| 宜兰县| 吉木乃县| 宣城市| 九江市| 五莲县| 洛川县| 江北区| 滨州市| 同江市| SHOW| 绥阳县| 竹北市| 甘孜| 建宁县| 监利县| 白城市| 耒阳市| 竹山县| 四川省| 屯留县| 谢通门县| 迁西县| 兰溪市| 铜梁县| 祁东县| 宁安市| 新竹县| 望都县| 万宁市| 西昌市| 濮阳县| 北碚区| 上犹县| 北川| 二手房| 耒阳市| 当阳市| 阿城市| 江孜县|