最新要闻
- 【世界速看料】充电慢犯法!iPhone 15若限制充电速度或违反欧盟法律
- 当前观点:词典笔迎来第三代!阿尔法蛋AI词典笔T20图赏
- 每日播报!旧车置换宝马新车?4S店销售“张伟”骗了13位车主200余万元
- 【世界播资讯】国内喝星巴克的人越来越少了引热议:至少30元/杯、国人消费理智、竞争加剧
- 焦点简讯:电影《红海行动2》今年开拍:前作票房超36亿 网友“自来水”安利
- 【全球快播报】10999元起 LG gram Style轻薄本开售:轻至999g
- 《黑暗荣耀2》演员被查有无校园暴力 空姐名场面是CG
- 【世界报资讯】《暗黑破坏神4》终极版宣传片发布:花100美元提前4天玩 还送坐骑等
- 当前最新:六分钟泡出武汉热干面 原汁味道!大汉口速食热干面大促:2.5元/袋
- 全球热议:借车给朋友车祸致人死亡!车主被判担责三成
- 实现内屏自动开合!魅族新折叠屏手机专利公布
- 天天讯息:2023年3月15日商丘嘉盛纸业A级箱板纸价格下调
- 每日信息:扫码点餐索要手机号违法吗?消保委暗访奶茶店和快餐店
- 全球热讯:山航就中国俄航等调侃信息发声明:不认同不符合客观事实的内容
- 东方甄选被曝养殖虾当野生虾卖 官方回应:被供应商骗了
- 【世界快播报】三星回应Galaxy S23 Ultra拍月亮“造假”:未进行任何图像叠加处理
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
环球今头条!记录--前端实现电子签名(web、移动端)通用
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
前言
在现在的时代发展中,从以前的手写签名,逐渐衍生出了电子签名。电子签名和纸质手写签名一样具有法律效应。电子签名目前主要还是在需要个人确认的产品环节和司法类相关的产品上较多。
举个常用的例子,大家都用过钉钉,钉钉上面就有电子签名,相信大家这肯定是知道的。
【资料图】
那作为前端的我们如何实现电子签名呢?其实在html5
中已经出现了一个重要级别的辅助标签,是啥呢?那就是canvas。
什么是canvas
Canvas(画布)
是在HTML5
中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript
操作的位图(bitmap)
。Canvas
对象表示一个 HTML
画布元素 -。它没有自己的行为,但是定义了一个 API 支持脚本化客户端绘图操作。
大白话就是canvas
是一个可以在上面通过javaScript
画图的标签,通过其提供的context(上下文)
及Api
进行绘制,在这个过程中canvas
充当画布的角色。
如何使用
canvas
给我们提供了很多的Api
,供我们使用,我们只需要在body
标签中创建一个canvas
标签,在script
标签中拿到canvas
这个标签的节点,并创建context(上下文)
就可以使用了。
... <script> // 获取canvas 实例 const canvas = document.querySelector("canvas") canvas.getContext("2d")</script>...
步入正题。
实现电子签名
知道几何的朋友都很清楚,线有点绘成,面由线绘成。
多点成线,多线成面。
所以我们实际只需要拿到当前触摸的坐标点,进行成线处理就可以了。
在body
中添加canvas
标签
在这里我们不仅需要在在body
中添加canvas
标签,我们还需要添加两个按钮,分别是取消
和保存
(后面我们会用到)。
添加文件
我这里全程使用js
进行样式设置及添加。
// 配置内容 const config = { width: 400, // 宽度 height: 200, // 高度 lineWidth: 5, // 线宽 strokeStyle: "red", // 线条颜色 lineCap: "round", // 设置线条两端圆角 lineJoin: "round", // 线条交汇处圆角 }
获取canvas
实例
这里我们使用querySelector
获取canvas
的dom实例,并设置样式和创建上下文。
// 获取canvas 实例 const canvas = document.querySelector("canvas") // 设置宽高 canvas.width = config.width canvas.height = config.height // 设置一个边框,方便我们查看及使用 canvas.style.border = "1px solid #000" // 创建上下文 const ctx = canvas.getContext("2d")
基础设置
我们将canvas
的填充色为透明,并绘制填充一个矩形,作为我们的画布,如果不设置这个填充背景色,在我们初识渲染的时候是一个黑色背景,这也是它的一个默认色。
// 设置填充背景色 ctx.fillStyle = "transparent" // 绘制填充矩形 ctx.fillRect( 0, // x 轴起始绘制位置 0, // y 轴起始绘制位置 config.width, // 宽度 config.height // 高度 );
上次绘制路径保存
这里我们需要声明一个对象,用来记录我们上一次绘制的路径结束坐标点及偏移量。
- 保存上次坐标点这个我不用说大家都懂;
- 为啥需要保存偏移量呢,因为鼠标和画布上的距离是存在一定的偏移距离,在我们绘制的过程中需要减去这个偏移量,才是我们实际的绘制坐标。
- 但我发现
chrome
中不需要减去这个偏移量,拿到的就是实际的坐标,之前在微信小程序中使用就需要减去偏移量,需要在小程序中使用的朋友需要注意这一点哦。
// 保存上次绘制的 坐标及偏移量 const client = { offsetX: 0, // 偏移量 offsetY: 0, endX: 0, // 坐标 endY: 0 }
设备兼容
我们需要它不仅可以在web
端使用,还需要在移动端
使用,我们需要给它做设备兼容处理。我们通过调用navigator.userAgent
获取当前设备信息,进行正则匹配判断。
// 判断是否为移动端 const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))
初始化
这里我们在监听鼠标按下(mousedown)
(web端)/触摸开始(touchstart)
的时候进行初始化,事件监听采用addEventListener
。
// 创建鼠标/手势按下监听器 window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
三元判断说明:这里当
mobileStatus
为true
时则表示为移动端
,反之则为web端
,后续使用到的三元
依旧是这个意思。
声明初始化方法
我们添加一个init
方法作为监听鼠标按下
/触摸开始
的回调方法。
这里我们需要获取到当前鼠标按下
/触摸开始
的偏移量和坐标,进行起始点绘制。
Tips:
web端
可以直接通过event
中取到,而移动端则需要在event.changedTouches[0]
中取到。
这里我们在初始化后再监听鼠标的移动。
// 初始化 const init = event => { // 获取偏移量及坐标 const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改上次的偏移量及坐标 client.offsetX = offsetX client.offsetY = offsetY client.endX = pageX client.endY = pageY // 清除以上一次 beginPath 之后的所有路径,进行绘制 ctx.beginPath() // 根据配置文件设置进行相应配置 ctx.lineWidth = config.lineWidth ctx.strokeStyle = config.strokeStyle ctx.lineCap = config.lineCap ctx.lineJoin = config.lineJoin // 设置画线起始点位 ctx.moveTo(client.endX, client.endY) // 监听 鼠标移动或手势移动 window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw) }
绘制
这里我们添加绘制draw
方法,作为监听鼠标移动
/触摸移动
的回调方法。
// 绘制 const draw = event => { // 获取当前坐标点位 const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改最后一次绘制的坐标点 client.endX = pageX client.endY = pageY // 根据坐标点位移动添加线条 ctx.lineTo(pageX , pageY ) // 绘制 ctx.stroke() }
结束绘制
添加了监听鼠标移动
/触摸移动
我们一定要记得取消监听并结束绘制,不然的话它会一直监听并绘制的。
这里我们创建一个cloaseDraw
方法作为鼠标弹起
/结束触摸
的回调方法来结束绘制并移除鼠标移动
/触摸移动
的监听。
canvas
结束绘制则需要调用closePath()
让其结束绘制
// 结束绘制 const cloaseDraw = () => { // 结束绘制 ctx.closePath() // 移除鼠标移动或手势移动监听器 window.removeEventListener("mousemove", draw) }
添加结束回调监听器
// 创建鼠标/手势 弹起/离开 监听器 window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw)
ok,现在我们的电子签名功能还差一丢丢可以实现完了,现在已经可以正常的签名了。
我们来看一下效果:
取消功能/清空画布
我们在刚开始创建的那两个按钮开始排上用场了。
这里我们创建一个cancel
的方法作为取消并清空画布使用
// 取消-清空画布 const cancel = () => { // 清空当前画布上的所有绘制内容 ctx.clearRect(0, 0, config.width, config.height) }
然后我们将这个方法和取消按钮
进行绑定
保存功能
这里我们创建一个save
的方法作为保存画布上的内容使用。
将画布上的内容保存为图片/文件
的方法有很多,比较常见的是blob
和toDataURL
这两种方案,但toDataURL
这哥们没blob
强,适配也不咋滴。所以我们这里采用a
标签 ➕ blob
方案实现图片的保存下载。
// 保存-将画布内容保存为图片 const save = () => { // 将canvas上的内容转成blob流 canvas.toBlob(blob => { // 获取当前时间并转成字符串,用来当做文件名 const date = Date.now().toString() // 创建一个 a 标签 const a = document.createElement("a") // 设置 a 标签的下载文件名 a.download = `${date}.png` // 设置 a 标签的跳转路径为 文件流地址 a.href = URL.createObjectURL(blob) // 手动触发 a 标签的点击事件 a.click() // 移除 a 标签 a.remove() }) }
然后我们将这个方法和保存按钮
进行绑定
我们将刚刚绘制的内容进行保存,点击保存按钮,就会进行下载保存
完整代码
Document <script> // 配置内容 const config = { width: 400, // 宽度 height: 200, // 高度 lineWidth: 5, // 线宽 strokeStyle: "red", // 线条颜色 lineCap: "round", // 设置线条两端圆角 lineJoin: "round", // 线条交汇处圆角 } // 获取canvas 实例 const canvas = document.querySelector("canvas") // 设置宽高 canvas.width = config.width canvas.height = config.height // 设置一个边框 canvas.style.border = "1px solid #000" // 创建上下文 const ctx = canvas.getContext("2d") // 设置填充背景色 ctx.fillStyle = "transparent" // 绘制填充矩形 ctx.fillRect( 0, // x 轴起始绘制位置 0, // y 轴起始绘制位置 config.width, // 宽度 config.height // 高度 ); // 保存上次绘制的 坐标及偏移量 const client = { offsetX: 0, // 偏移量 offsetY: 0, endX: 0, // 坐标 endY: 0 } // 判断是否为移动端 const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent)) // 初始化 const init = event => { // 获取偏移量及坐标 const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改上次的偏移量及坐标 client.offsetX = offsetX client.offsetY = offsetY client.endX = pageX client.endY = pageY // 清除以上一次 beginPath 之后的所有路径,进行绘制 ctx.beginPath() // 根据配置文件设置相应配置 ctx.lineWidth = config.lineWidth ctx.strokeStyle = config.strokeStyle ctx.lineCap = config.lineCap ctx.lineJoin = config.lineJoin // 设置画线起始点位 ctx.moveTo(client.endX, client.endY) // 监听 鼠标移动或手势移动 window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw) } // 绘制 const draw = event => { // 获取当前坐标点位 const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event // 修改最后一次绘制的坐标点 client.endX = pageX client.endY = pageY // 根据坐标点位移动添加线条 ctx.lineTo(pageX , pageY ) // 绘制 ctx.stroke() } // 结束绘制 const cloaseDraw = () => { // 结束绘制 ctx.closePath() // 移除鼠标移动或手势移动监听器 window.removeEventListener("mousemove", draw) } // 创建鼠标/手势按下监听器 window.addEventListener(mobileStatus ? "touchstart" : "mousedown", init) // 创建鼠标/手势 弹起/离开 监听器 window.addEventListener(mobileStatus ? "touchend" :"mouseup", cloaseDraw) // 取消-清空画布 const cancel = () => { // 清空当前画布上的所有绘制内容 ctx.clearRect(0, 0, config.width, config.height) } // 保存-将画布内容保存为图片 const save = () => { // 将canvas上的内容转成blob流 canvas.toBlob(blob => { // 获取当前时间并转成字符串,用来当做文件名 const date = Date.now().toString() // 创建一个 a 标签 const a = document.createElement("a") // 设置 a 标签的下载文件名 a.download = `${date}.png` // 设置 a 标签的跳转路径为 文件流地址 a.href = URL.createObjectURL(blob) // 手动触发 a 标签的点击事件 a.click() // 移除 a 标签 a.remove() }) }</script>
各内核和浏览器支持情况
Mozilla 程序从 Gecko 1.8 (Firefox 1.5(en-US)) 开始支持。它首先是由 Apple 引入的,用于 OS X Dashboard 和 Safari。Internet Explorer 从 IE9 开始支持
,更旧版本的 IE 中,页面可以通过引入 Google 的Explorer Canvas项目中的脚本来获得
支持。Google Chrome 和 Opera 9+ 也支持
。
小程序中提示
在小程序中我们如果需呀实现的话,也是同样的原理哦,只是我们需要将创建实例和上下文
的Api
进行修改,因为小程序中是没有dom
,既然没有dom
,哪来的操作dom
这个操作呢。
如果是
uni-app
则需要使用uni.createCanvasContext进行上下文创建如果是原生微信小程序则使用
wx.createCanvasContext
进行创建(2.9.0)之后的库不支持
本文转载于:
https://juejin.cn/post/7174251833773752350
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
关键词:
-
当前速读:Linux LVM磁盘分区管理
源文档地址:https: www 2daygeek com create-lvm-storage-logical-volume-manager-in-linux 1 创建PV创建前 dev
来源: 当前速读:Linux LVM磁盘分区管理
环球今头条!记录--前端实现电子签名(web、移动端)通用
新动态:GPT-4 重磅发布,用户直呼:强得离谱
【聚看点】Python处理Unicode字符时出现中文乱码的情况
世界今亮点!go开发入门篇之go语言
【世界速看料】充电慢犯法!iPhone 15若限制充电速度或违反欧盟法律
当前观点:词典笔迎来第三代!阿尔法蛋AI词典笔T20图赏
每日播报!旧车置换宝马新车?4S店销售“张伟”骗了13位车主200余万元
【世界播资讯】国内喝星巴克的人越来越少了引热议:至少30元/杯、国人消费理智、竞争加剧
焦点简讯:电影《红海行动2》今年开拍:前作票房超36亿 网友“自来水”安利
【全球快播报】10999元起 LG gram Style轻薄本开售:轻至999g
天天新动态:HTML/XML字符转义对照表
环球新消息丨易基因:高通量测序后的下游实验验证方法——ChIP-seq篇|干货系列
焦点观察:爬虫-requests
记一次运气非常好的服务器渗透经历
【环球快播报】Chrome高级调试技巧
《黑暗荣耀2》演员被查有无校园暴力 空姐名场面是CG
【世界报资讯】《暗黑破坏神4》终极版宣传片发布:花100美元提前4天玩 还送坐骑等
当前最新:六分钟泡出武汉热干面 原汁味道!大汉口速食热干面大促:2.5元/袋
全球热议:借车给朋友车祸致人死亡!车主被判担责三成
实现内屏自动开合!魅族新折叠屏手机专利公布
全球简讯:外网信息搜集
每日热门:这啥?竟能让羊毛党无能狂怒!|无感验证还不快来体验
全球快讯:02.SQL
通过随机数Random 和 redis的incr每次增加一的原子性来动态绑定队列
uniapp,常用工具函数
天天讯息:2023年3月15日商丘嘉盛纸业A级箱板纸价格下调
每日信息:扫码点餐索要手机号违法吗?消保委暗访奶茶店和快餐店
全球热讯:山航就中国俄航等调侃信息发声明:不认同不符合客观事实的内容
东方甄选被曝养殖虾当野生虾卖 官方回应:被供应商骗了
【世界快播报】三星回应Galaxy S23 Ultra拍月亮“造假”:未进行任何图像叠加处理
世界聚焦:不给友商留机会 GPT-4大量技术细节不再公开:安全更重要
天天观焦点:CentOS 7 安装 YApi
易基因:染色质免疫共沉淀测序(ChIP-seq)的数据挖掘思路 |干货系列
fabric使用
当前简讯:企业微信对接openai实现chatgpt3.5聊天机器人
焦点快报!濒死恒星演化成超新星前一幕被韦伯捕捉:壮观至极!
全球热议:OpenAI还在烧钱 但开发者已经利用GPT挣钱了:还是国产的
FIFA官宣2026世界杯改制:48队分为12个组 赛事总场次增至104场
环球即时:合肥发布新能源汽车消费补贴政策:最高补贴5000元
环球动态:真不用羡慕油车了!特斯拉V4超级充电桩落地:最高功率350kW
全球快资讯:VMware安装虚拟机时提示错误"Failed to install the hcmon driver."解决办法
环球即时看!C# || 批量翻译工具 || 百度翻译api || 读取.cs文件内容 || 正则表达式筛选文件
这是一篇纯讲SQL语句优化的文章!!!| 博学谷狂野架构师
消息!前端架构工作
【全球速看料】Linux进程通信 | 管道与FIFO
全球微速讯:智动力:目前暂未涉及6G通信网络相关领域
焦点速讯:你支持吗?快递不告而放或最高可罚3万 直接放菜鸟也不接受?
【天天速看料】哪吒汽车跟进90天保价 哪吒S 1160增程小版限时17.98万元
林依晨和郑元畅在一起过吗?林依晨和郑元畅参加的综艺节目叫什么?
泰坦尼克号是真实的故事吗?泰坦尼克号的男女主角叫什么?
前锋燃气灶质量怎么样?燃气灶十大品牌排行榜
iis是什么软件?iis在哪里打开?
aspx文件是什么?aspx文件怎么打开?
Prime95烤机教程
观点:成人崩溃就在一瞬间 外卖小哥酒后误上高速 电量跑光痛哭不止
全球今头条!生产环境触目惊心!汕头知名橄榄菜企业被连夜查处:线上平台火速下架
播报:全周期订单数突破35万!魅族20系列无界超前订圆满结束
湖南邵阳疑似挖出龙化石?当地回应:或为天然石头
世界视点!Model Y行驶中刹车变硬 车主:售后说是常态化事情
GPT-4上线:史上最强大多模态语言模型,堪称最强人工智能,目前OpenAI付费升级GPT-4平台已崩溃
观点:报复性消费来了:我国网上零售额月均破万亿元
16岁女孩将挑战珠峰 父亲众筹50万 回应来了:女儿想法
奔驰EQC刚买半年驱动电机就被烧毁 车主质疑4S店故意欺诈
环球新动态:电机品牌排行榜_电机品牌
环球速递!文盘Rust -- 安全连接 TiDB/Mysql
自从用了 EasyExcel,导入导出 Excel 更简单了!
浅谈var,let,const
今日最新!Maven学习笔记3:在idea中使用Maven
全球播报:玩家最喜欢的复古游戏TOP5:《俄罗斯方块》排第二
环球快资讯:程序员也危险了!GPT-4十秒即可生成一个网站
焦点消息!ChatGPT升级为GPT-4 会看图懂幽默 细思极恐
充电慢、续航差、反馈无门!bZ3X首批车主公开致信广汽丰田董事长
不接董事长电话1次罚1万元 公司回应:合不合法你说了不算
项目构建node-sass源码报错 SyntaxError:Unexpectedtoken"?"
前端设计模式——命令模式
【热闻】保时捷去年净赚499亿元:国人给力 中国连续八年为最大市场
打工几年就能买北京四合院?新剧《心想事成》开播引热议
男子辞职摆摊拍照 1月内激增14家同行 建议大家好好上班
快资讯丨Meta宣布再裁员上万人 连HR都裁了!扎克伯格给出理由
【世界新视野】韩国SBS电视台回应剪辑杨紫琼感言:未刻意针对女性
焦点报道:3月15日热股前瞻:7股突发利好
今日报丨建议收藏chatGPT说的Ubuntu下常用网络命令合集
【天天热闻】315来临!消费者起诉东方甄选 官方:我们也被供应商骗了
环球即时看!网文连载十余年被网友举报 1万多章还没结尾:作者回应了
每日快看:2022年新能源汽车投诉量增长62.84%:行驶中突然熄火、漏油成热点
世界信息:高速免费!2023年清明节放假通知来了:1天假 不调休
每日看点!苹果为何不做电视?真实原因揭开
2023年安卓之光!小米13 Ultra曝光:支持可变光圈
读Java性能权威指南(第2版)笔记17_垃圾回收D
刚刚,拜登最新表态!两大重磅降临,欧美多头集体沸腾!危机一闪而过?这家巨头突然"捅刀"
拒绝卡脖子 我国掌握量子计算核心技术:低温接近绝对零度
4家汽车公司明确不打价格战 定位豪华品牌:特斯拉比亚迪看笑
如何用好免费的chatGPT
全球观焦点:算法模板总结 1
【独家焦点】预算3000元 找老鸟装了台12代U ITX小主机:这配置你看如何?
天天视讯!AMD最强核显跑分逆天!竟然逼平GTX 1650、RX 480
热点在线丨女演员被困五星级酒店厕所超3小时!酒店回应:属于特例
头条焦点:《速度与激情10》新海报发布:范迪塞尔携众家人再度狂飙
深圳带奶茶跑腿回港火了:一趟就能赚数百元