網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
開啟生長(zhǎng)之旅!這是我參加「日新方案 12 月更文挑戰(zhàn)」的第15天,點(diǎn)擊檢查活動(dòng)概況
前語(yǔ)
在現(xiàn)在的年代發(fā)展中,從以前的手寫簽名,逐步衍生出了電子簽名。電子簽名和紙質(zhì)手寫簽名一樣具有法令效應(yīng)。電子簽名現(xiàn)在主要還是在需求個(gè)人確認(rèn)的產(chǎn)品環(huán)節(jié)和司法類相關(guān)的產(chǎn)品上較多。
舉個(gè)常用的例子,咱們都用過(guò)釘釘,釘釘上面就有電子簽名,信任咱們這肯定是知道的。
那作為前端的咱們?cè)趺赐瓿呻娮雍灻兀科鋵?shí)在html5中現(xiàn)已呈現(xiàn)了一個(gè)重要級(jí)別的輔佐標(biāo)簽,是啥呢?那就是canvas。
什么是canvas
Canvas(畫布)是在HTML5中新增的標(biāo)簽用于在網(wǎng)頁(yè)實(shí)時(shí)生成圖畫,并且能夠操作圖畫內(nèi)容,基本上它是一個(gè)能夠用JavaScript操作的位圖(bitmap)。Canvas 目標(biāo)表明一個(gè) HTML 畫布元素 -。它沒(méi)有自己的行為,但是界說(shuō)了一個(gè) API 支撐腳本化客戶端繪圖操作。
大白話就是canvas是一個(gè)能夠在上面經(jīng)過(guò)javaScript畫圖的標(biāo)簽,經(jīng)過(guò)其供給的context(上下文)及Api進(jìn)行制作,在這個(gè)過(guò)程中canvas充任畫布的角色。
怎么運(yùn)用
canvas給咱們供給了許多的Api,供咱們運(yùn)用,咱們只需求在body標(biāo)簽中創(chuàng)立一個(gè)canvas標(biāo)簽,在script標(biāo)簽中拿到canvas這個(gè)標(biāo)簽的節(jié)點(diǎn),并創(chuàng)立context(上下文)就能夠運(yùn)用了。
…
... 步入正題。完成電子簽名
知道幾許的朋友都很清楚,線有點(diǎn)繪成,面由線繪成。
多點(diǎn)成線,多線成面。
所以咱們實(shí)踐只需求拿到當(dāng)時(shí)接觸的坐標(biāo)點(diǎn),進(jìn)行成線處理就能夠了。
在body中增加canvas標(biāo)簽
在這兒咱們不僅需求在在body中增加canvas標(biāo)簽,咱們還需求增加兩個(gè)按鈕,分別是撤銷和保存(后面咱們會(huì)用到)。
// 裝備內(nèi)容
const config = {
width: 400, // 寬度
height: 200, // 高度
lineWidth: 5, // 線寬
strokeStyle: ‘red’, // 線條色彩
lineCap: ‘round’, // 設(shè)置線條兩頭圓角
lineJoin: ‘round’, // 線條交匯處圓角
}
獲取canvas實(shí)例
這兒咱們運(yùn)用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è)邊框,方便咱們檢查及運(yùn)用
canvas.style.border = '1px solid #000'
// 創(chuàng)立上下文
const ctx = canvas.getContext('2d')
基礎(chǔ)設(shè)置
咱們將canvas的填充色為透明,并制作填充一個(gè)矩形,作為咱們的畫布,假如不設(shè)置這個(gè)填充背景色,在咱們初識(shí)渲染的時(shí)候是一個(gè)黑色背景,這也是它的一個(gè)默認(rèn)色。
// 設(shè)置填充背景色
ctx.fillStyle = 'transparent'
// 制作填充矩形
ctx.fillRect(
0, // x 軸開端制作方位
0, // y 軸開端制作方位
config.width, // 寬度
config.height // 高度
);
前次制作途徑保存
這兒咱們需求聲明一個(gè)目標(biāo),用來(lái)記錄咱們上一次制作的途徑完畢坐標(biāo)點(diǎn)及偏移量。
保存前次坐標(biāo)點(diǎn)這個(gè)我不用說(shuō)咱們都懂;
為啥需求保存偏移量呢,由于鼠標(biāo)和畫布上的間隔是存在必定的偏移間隔,在咱們制作的過(guò)程中需求減去這個(gè)偏移量,才是咱們實(shí)踐的制作坐標(biāo)。
但我發(fā)現(xiàn)chrome中不需求減去這個(gè)偏移量,拿到的就是實(shí)踐的坐標(biāo),之前在微信小程序中運(yùn)用就需求減去偏移量,需求在小程序中運(yùn)用的朋友需求注意這一點(diǎn)哦。
// 保存前次制作的 坐標(biāo)及偏移量
const client = {
offsetX: 0, // 偏移量
offsetY: 0,
endX: 0, // 坐標(biāo)
endY: 0
}
設(shè)備兼容
咱們需求它不僅能夠在web端運(yùn)用,還需求在移動(dòng)端運(yùn)用,咱們需求給它做設(shè)備兼容處理。咱們經(jīng)過(guò)調(diào)用navigator.userAgent獲取當(dāng)時(shí)設(shè)備信息,進(jìn)行正則匹配判別。
// 判別是否為移動(dòng)端
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))
初始化
這兒咱們?cè)诒O(jiān)聽鼠標(biāo)按下(mousedown)(web端)/接觸開端(touchstart)的時(shí)候進(jìn)行初始化,事情監(jiān)聽采用addEventListener。
// 創(chuàng)立鼠標(biāo)/手勢(shì)按下監(jiān)聽器
window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
三元判別闡明: 這兒當(dāng)mobileStatus為true時(shí)則表明為移動(dòng)端,反之則為web端,后續(xù)運(yùn)用到的三元依舊是這個(gè)意思。
聲明初始化辦法
咱們?cè)黾右粋€(gè)init辦法作為監(jiān)聽鼠標(biāo)按下/接觸開端的回調(diào)辦法。
這兒咱們需求獲取到當(dāng)時(shí)鼠標(biāo)按下/接觸開端的偏移量和坐標(biāo),進(jìn)行開端點(diǎn)制作。
Tips:web端能夠直接經(jīng)過(guò)event中取到,而移動(dòng)端則需求在event.changedTouches[0]中取到。
這兒咱們?cè)诔跏蓟笤俦O(jiān)聽鼠標(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è)置畫線開端點(diǎn)位
ctx.moveTo(client.endX, client.endY)
// 監(jiān)聽 鼠標(biāo)移動(dòng)或手勢(shì)移動(dòng)
window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
}
制作
這兒咱們?cè)黾又谱鱠raw辦法,作為監(jiān)聽鼠標(biāo)移動(dòng)/接觸移動(dòng)的回調(diào)辦法。
// 制作
const draw = event => {
// 獲取當(dāng)時(shí)坐標(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ān)聽鼠標(biāo)移動(dòng)/接觸移動(dòng)咱們必定要記住撤銷監(jiān)聽并完畢制作,不然的話它會(huì)一直監(jiān)聽并制作的。
這兒咱們創(chuàng)立一個(gè)cloaseDraw辦法作為鼠標(biāo)彈起/完畢接觸的回調(diào)辦法來(lái)完畢制作并移除鼠標(biāo)移動(dòng)/接觸移動(dòng)的監(jiān)聽。
canvas完畢制作則需求調(diào)用closePath()讓其完畢制作
// 完畢制作
const cloaseDraw = () => {
// 完畢制作
ctx.closePath()
// 移除鼠標(biāo)移動(dòng)或手勢(shì)移動(dòng)監(jiān)聽器
window.removeEventListener("mousemove", draw)
}
增加完畢回調(diào)監(jiān)聽器
// 創(chuàng)立鼠標(biāo)/手勢(shì) 彈起/離開 監(jiān)聽器
window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw)
ok,現(xiàn)在咱們的電子簽名功能還差一丟丟能夠完成完了,現(xiàn)在現(xiàn)已能夠正常的簽名了。
咱們來(lái)看一下作用:
撤銷功能/清空畫布
咱們?cè)趧傞_端創(chuàng)立的那兩個(gè)按鈕開端排上用場(chǎng)了。
這兒咱們創(chuàng)立一個(gè)cancel的辦法作為撤銷并清空畫布運(yùn)用
// 撤銷-清空畫布
const cancel = () => {
// 清空當(dāng)時(shí)畫布上的一切制作內(nèi)容
ctx.clearRect(0, 0, config.width, config.height)
}
然后咱們將這個(gè)辦法和撤銷按鈕進(jìn)行綁定
<button onclick="cancel()">撤銷</button>
保存功能
這兒咱們創(chuàng)立一個(gè)save的辦法作為保存畫布上的內(nèi)容運(yùn)用。
將畫布上的內(nèi)容保存為圖片/文件的辦法有許多,比較常見的是blob和toDataURL這兩種方案,但toDataURL這哥們沒(méi)blob強(qiáng),適配也不咋滴。所以咱們這兒采用a標(biāo)簽 ? blob方案完成圖片的保存下載。
// 保存-將畫布內(nèi)容保存為圖片
const save = () => {
// 將canvas上的內(nèi)容轉(zhuǎn)成blob流
canvas.toBlob(blob => {
// 獲取當(dāng)時(shí)時(shí)間并轉(zhuǎn)成字符串,用來(lái)作為文件名
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)行下載保存
前端完成電子簽名(web、移動(dòng)端)通用
完整代碼
小程序中提示
在小程序中咱們假如需呀完成的話,也是同樣的原理哦,只是咱們需求將創(chuàng)立實(shí)例和上下文的Api進(jìn)行修正,由于小程序中是沒(méi)有dom,既然沒(méi)有dom,哪來(lái)的操作dom這個(gè)操作呢。
假如是uni-app則需求運(yùn)用uni.createCanvasContext進(jìn)行上下文創(chuàng)立
假如是原生微信小程序則運(yùn)用wx.createCanvasContext進(jìn)行創(chuàng)立(2.9.0)之后的庫(kù)不支撐
原文鏈接:https://blog.csdn.net/zhangyizuishuai/article/details/131742145
- 上一篇:沒(méi)有了
- 下一篇:沒(méi)有了
相關(guān)推薦
- 2024-03-04 layui tree組件實(shí)現(xiàn)搜索節(jié)點(diǎn)并展開
- 2022-09-02 使用Docker配置redis?sentinel哨兵的方法步驟_docker
- 2022-09-13 iOS實(shí)現(xiàn)手動(dòng)和自動(dòng)屏幕旋轉(zhuǎn)_IOS
- 2022-04-05 C#反射調(diào)用拓展類方法實(shí)例代碼_C#教程
- 2022-05-08 Pandas修改DataFrame列名的兩種方法實(shí)例_python
- 2022-07-24 示例剖析golang中的CSP并發(fā)模型_Golang
- 2023-01-07 python導(dǎo)入其他目錄下模塊的四種情況_python
- 2023-08-30 liunx shell腳本并發(fā)控制詳解
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支