uniapp微信小程序电子签名
先上效果图,不满意可以直接关闭这页签


新建成单独的组件,然后具体功能引入,具体功能点击签名按钮,把当前功能页面用样式隐藏掉,v-show和v-if也行,然后再把这个组件显示出来。
【签名-撤销】原理是之前绘画时把全部轨迹路径都记录下来,然后点击撤销时,清空画布,路径数组去掉最后一次绘画动作,然后再把剩余路径又全部画上去,这么干后会路径会出现锯齿,我也莫得办法了,将就着用了。
【签名-完成】点击完成会判断路径数组是否有值,如果没有则说明没有签名,有则把画布保存成图片,然后再把这个图片以指定尺寸画入另一个画布,避免保存下来的图片分辨率过大,导致文件太大。画上另一个画布之后,这个画布再保存成图片,然后图片再转成base64格式返回给主页面,要是不想转base64可以把具体代码去掉。生成的图片是垂直,应该以逆时针旋转90度保存的,奈何前端实力不过关,怎么都处理不好这个逆时针旋转90度,只能在上传到后端后,用后端旋转了(丢人).........如果有人能处理好这个,麻烦评论留下代码
主页面引入组件并注册,然后用v-show控制是否显示,主页面样式自己调整好,让电子签名可以覆盖整个页面。

[具体组件代码]
<template><view class="panel" :style="{top: `${top}px`}"><canvas canvas-id="signCanvas" class="sign-canvas" @touchstart="handleTouchStart"@touchmove="handleTouchMove" @touchend="handleTouchEnd"></canvas><!-- 另一个画布,用来缩小签名图片尺寸的,加个样式让他飞到外太空去 --><canvas canvas-id="signCanvasReduce" class="sign-canvas-reduce"></canvas><view class="panel-bottom"><view class="panel-bottom-btn btn-gray" @click="onCancel">取消</view><view class="panel-bottom-btn btn-gray" @click="onUndo">撤销</view><view class="panel-bottom-btn btn-gray" @click="onClearRect(true)">重写</view><view class="panel-bottom-btn" @click="onSaveSign">完成</view></view></view>
</template><script>export default {data() {return {// 距离顶部高度top: void (0),isDrawing: false,startX: 0,startY: 0,strokes: [],canvasWidth: 0,canvasHeight: 0}},mounted() {// 获取手机状态栏和导航栏高度,和手机屏幕可用宽高度const _this = thisuni.getSystemInfo({success: function(res) {_this.canvasWidth = res.windowWidth_this.canvasHeight = res.windowHeightconst custom = uni.getMenuButtonBoundingClientRect()// 导航栏胶囊高度 + (胶囊距离顶部高度 - 状态栏高度) * 2 + 状态栏高度 + 20内边距_this.top = custom.height + (custom.top - res.statusBarHeight) * 2 + res.statusBarHeight + 4}})// 创建画布const ctx = uni.createCanvasContext('signCanvas', this)ctx.setStrokeStyle('#000')ctx.setLineWidth(4)ctx.setLineCap('round')ctx.setLineJoin('round')ctx.draw()this.canvasContext = ctx},methods: {handleTouchStart(e) {// 阻止默认滚动行为e.preventDefault()const touch = e.touches[0]this.isDrawing = truethis.startX = touch.xthis.startY = touch.ythis.strokes.push({type: 'start',x: touch.x,y: touch.y})},handleTouchMove(e) {e.preventDefault() // 阻止默认滚动行为if (!this.isDrawing) {return}const touch = e.touches[0]this.canvasContext.moveTo(this.startX, this.startY)this.canvasContext.lineTo(touch.x, touch.y)this.canvasContext.stroke()this.canvasContext.draw(true)this.startX = touch.xthis.startY = touch.ythis.strokes.push({type: 'move',x: touch.x,y: touch.y})},handleTouchEnd(e) {e.preventDefault() // 阻止默认滚动行为this.isDrawing = false},// 撤销onUndo () {// 先清空当前画布this.onClearRect(false)if (this.strokes.length) {// 去掉最后一次绘画的路径while (this.strokes.pop().type !== 'start'){}// 剩余路径全部绘制到画布上for (let i = 0; i < this.strokes.length; i++) {const item = this.strokes[i]if(item.type === 'start') {// 绘制起始点this.canvasContext.beginPath()this.canvasContext.moveTo(item.x, item.y)} else if(item.type === 'move') {// 绘制线条this.canvasContext.lineTo(item.x, item.y)this.canvasContext.stroke()}}this.canvasContext.draw(true)}},// 清空onClearRect (clearLine) {this.canvasContext.clearRect(0, 0, this.canvasWidth, this.canvasHeight)this.canvasContext.draw(true)clearLine && (this.strokes = [])},// 取消onCancel () {this.onClearRect(true)this.$emit('cancel')},// 保存签名 signFlag 是否已签名onSaveSign() {if (!this.strokes.length) {// 未签名this.$emit('ok', { signFlag: false })return}// 签名保存为图片uni.canvasToTempFilePath({canvasId: 'signCanvas',quality: 0.1,success: (res) => {const tempPath = res.tempFilePath// 然后写入另一个画布const signCanvas = uni.createCanvasContext('signCanvasReduce', this)signCanvas.translate(0, 0) // 修改原点坐标(这里是已左上角为坐标原点)signCanvas.drawImage(tempPath, 0, 0, 80, 160)signCanvas.draw(false, () => {setTimeout(() => {// 另一个画布再保存为图片,目的就是缩小图片的尺寸uni.canvasToTempFilePath({canvasId: 'signCanvasReduce',quality: 0.2,success: (res) => {// 清空画布this.onClearRect(true)// 转成base64this.imagePathToBase64(res.tempFilePath).then(base64 => {this.$emit('ok', { base64, signFlag: true })})},fail: () => {// toast('生成签名图片失败')}}, this)}, 200)})},fail: (res) => {// toast('生成签名失败')}}, this)},// 根据上传后的图片转成Base64格式imagePathToBase64(url) {if (!url) {return url}return new Promise((resolve, reject) => {uni.getFileSystemManager().readFile({filePath: url,encoding: 'base64',success: fileRes => {const base64 = 'data:image/png;base64,' + fileRes.dataresolve(base64)},fail: err => {// toast('生成签名失败')resolve()}})})}}}
</script><style lang="scss" scoped>.panel {width: 100%;position: absolute;left: 0;bottom: 0;right: 0;top: 0;overflow-y: hidden;background-color: #FFF;}.sign-canvas {width: 100%;height: 85%;}.sign-canvas-reduce {width: 80px;height: 160px;position: absolute;top: -10000rpx;}.panel-bottom {height: 15%;display: flex;justify-content: center;padding-top: 50rpx;}.panel-bottom-btn {transform: rotate(90deg);height: 40rpx;padding: 14rpx 36rpx;font-size: 30rpx;border-radius: 20rpx;color: #FFF;background: linear-gradient(90deg, rgba(250, 197, 22, 1), rgba(255, 141, 26, 1));}.btn-gray {background: #d4d4d4;}
</style>
<style>page {overflow-y: hidden;}
</style>
继续加班了.....
码字不易,于你有利,勿忘点赞
相关文章:
uniapp微信小程序电子签名
先上效果图,不满意可以直接关闭这页签 新建成单独的组件,然后具体功能引入,具体功能点击签名按钮,把当前功能页面用样式隐藏掉,v-show和v-if也行,然后再把这个组件显示出来。 【签名-撤销】原理是之前绘画时…...
MetaPoint_速读
Meta-Point Learning and Refining for Category-Agnostic Pose Estimation https://arxiv.org/abs/2404.14808https://github.com/chenbys/metapointabstract 这篇文章介绍了一种名为Meta-Point Learning and Refining的框架,用于实现类别不可知的姿势估计。该框…...
数据库逆向工程工具reverse_sql
reverse_sql 是一个用于解析和转换 MySQL 二进制日志(binlog)的工具。它可以将二进制日志文件中记录的数据库更改操作(如插入、更新、删除)转换为反向的 SQL 语句,以便对系统或人为产生的误操作进行数据回滚和恢复。 *…...
四大内网穿透利器对比
本文精选四款市场上的佼佼者——巴比达、花生壳、Frp及NatApp,详细剖析它们的特点与优势,助力企业和个人用户精准选择,其中特别强调了巴比达在企业级安全访问方面的突出贡献。 1. 巴比达 特点 深度安全防护:巴比达提供全方位安…...
【LeetCode】每日一题:跳跃游戏 II
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最小…...
SpringBoot拦截器
目录 一、拦截器快速入门 (1)什么是拦截器 (2)拦截器的使用步骤 1、定义拦截器 🍀preHandle() 方法 🍀postHandle() 方法 🍀afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…...
uniapp中实现跳转链接到游览器(安卓-h5)
uniapp中实现跳转链接到游览器(安卓-h5) 项目中需要做到跳转到外部链接,网上找了很多都不是很符合自己的要求,需要编译成app后是跳转到游览器打开链接,编译成web是在新窗口打开链接。实现的代码如下: 效果&…...
WPF UI 界面布局 魔术棒 文字笔记识别 技能提升 布局功能扩展与自定义 继承Panel的对象,测量与排列 系列七
应用开发第一步 功能分类:页面上的功能区域划分。。。。需求分析 业务逻辑 数据流 功能模块 UI/UX 编码 测试 发布 功能开发与布局 不用显式的方式设定元素的尺寸 不使用屏幕坐标来指定位置 Grid 功能最强大,布局最灵活的容器…...
文件格式是.pb应该怎么查看?
文件格式为.pb的文件,通常是Google Protocol Buffers(简称PB)序列化后的二进制文件。要查看.pb文件的内容,可以采用以下方法: 1. **直接打开(不推荐)**: - 直接打开.pb文件通常会显示…...
android2024 gradle8 Processor和ksp两种编译时注解实现
android编译时注解,老生常谈,外面的例子都是bindView,脑壳看疼了,自己学习和编写下。 而且现在已经进化到kotlin2.0,google也逐渐放弃kapt,进入维护状态。所以要好好看看本贴。 参考我的工程: h…...
elementui的table的@selection-change阻止事件改变
说明: 最近有个不想说的(xxx)业务,在表格勾选每一行的时候要触发一系列查询功能,查询失败还要把那个勾勾回退。真实蛋疼!表格勾选的默认selection-change是change事件,一般change事件是在完成之…...
空间数据采集与管理:为什么选择ArcGISPro和Python?
你还在为找不到合适的数据而苦恼吗?你还在面对大量数据束手无策,不知如何处理吗?对于从事生产和科研的人员来说,空间数据的采集与管理是地理信息系统(GIS)和空间分析领域的关键环节。通过准确高效地采集和管…...
案例精选 | 聚铭综合日志分析系统为江苏省电子口岸构建高效安全的贸易生态
江苏省电子口岸有限公司,成立于2009年,由江苏省贸促会携手南京海关、江苏检验检疫局及江苏海事局等部门共同出资组建。公司承载着推动江苏乃至长三角地区国际贸易便利化的重大使命,致力于打造一个集先进性、创新性、高效性于一体的电子口岸综…...
TCP粘包
目录 TCP粘包产生的原因 TCP粘包的现象 TCP粘包的解决方案 TCP粘包是指在TCP通信中,发送方发送的多个数据包在接收方被错误地合并成一个数据包的现象。tcp粘包在发送端和接收端都有可能发生。发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包。接收方粘包:接收方不及…...
数据泄露态势(2024年5月)
监控说明:以下数据由零零信安0.zone安全开源情报系统提供,该系统监控范围包括约10万个明网、深网、暗网、匿名社交社群威胁源。在进行抽样事件分析时,涉及到我国的数据不会选取任何政府、安全与公共事务的事件进行分析。如遇到影响较大的伪造…...
二手闲置平台小程序的设计
管理员账户功能包括:系统首页,个人中心,用户管理,卖家管理,商品分类管理,商品信息管理,商品购买管理,商品配送管理 微信端账号功能包括:系统首页,商品信息&a…...
协程libgo的使用
c开源协程库libgo介绍及使用-CSDN博客 libgo库的github地址:GitHub - yyzybb537/libgo: Go-style concurrency in C11 使用libgo编写并行程序,即可以像golang一样开发迅速且逻辑简洁,又有C原生的性能优势。它的特点有: 1.提供go…...
什么叫低频晶振?低频晶振最低频率能达到多少?低频晶振封装尺寸有哪些?
低频晶振指的是那些工作在较低频率范围内的晶体振荡器,通常这类振荡器的标称频率低于8MHz。这些晶振在各种电子设备中都有应用,尤其是在那些需要精确但不需要高频振荡的应用场景中,比如实时时钟(RTC)、低速串行通信接口(如UART、IC等)、以及一…...
Splunk Enterprise 任意文件读取漏洞(CVE-2024-36991)
文章目录 前言漏洞描述影响版本漏洞复现POC批量检测-nuclei脚本 修复建议 前言 Splunk Enterprise 是一款强大的机器数据管理和分析平台,能够实时收集、索引、搜索、分析和可视化来自各种数据源的日志和数据,帮助企业提升运营效率、增强安全性和优化业务…...
零基础STM32单片机编程入门(九)IIC总线详解及EEPROM实战含源码视频
文章目录 一.概要二.IIC总线基本概念1.总体特征2.通讯流程 三.EEPROM介绍1.M24C08基本介绍2.向M24C08写一个字节时序图3.从M24C08读一个字节时序图 四.GPIO模拟IIC驱动M24C08读写五.CubeMX工程源代码下载六.讲解视频链接地址七.小结 一.概要 IIC(Inter-Integrated …...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...
路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...
