Taro+nutui h5使用nut-signature 签名组件的采坑记录

news2024/11/16 0:54:16

近期在使用Taro(“@tarojs/taro”: “3.4.0-beta.0”) + Nutui (3.1.16)开发H5时,需要一个签名功能结果在小程序上运行正常的 nut-signature组件,在h5上出问题了
首先问题是 :

Nutui的 签名组件(nut-signature)不能签名

在小程序中是可以正常使用,结果打包成h5就不行了,???
代码追踪+源码追踪,直接原因是:
在h5上
在这里插入图片描述
也就是在源码这个在这里插入图片描述
原因: Taro.createSelectorQuery().select("#spcanvas").fields 在数据返回时 res中本该包含node节点的但是在h5上没有,获取canvas节点未获取到导致在h5中签名失败

虽然官网上fields方法是兼容H5的但是这个地方就是没有获取到节点 -.-

解决方案: 用canvas,自己实现签名组件(小程序)

组件大致长这样
请添加图片描述
完整组件地址完整代码

实现逻辑就是 监听canvas的 touchstart、touchmove、touchend、touchleave事件
签名大致就是起笔,落笔 连线,收笔,想象自己写字的动作.
以vue举例,其他同理:

html代码部分

<div class="pad-20">
        <div class="written">
            <div id="canvas-content" style="width: 100%; height: 100%">
                <canvas
                    class="canvasSign"
                    id="canvasSign"
                    @touchstart="startEventHandler"
                    @touchmove="moveEventHandler"
                    @touchend="endEventHandler"
                    @touchleave="leaveEventHandler"
                />
            </div>

            <div class="flex-center">
                <button class="button_clear button" @click="() => clearClick()">重签</button>
                <button class="button_submit button" @click="() => saveClick()">确认</button>
            </div>
        </div>
    </div>

js部分

  1. 初始化数据
  2. 初始化画布
  3. 监听画布的toch事件
let content: any = null; // canvas 的 绘图工具对象

// 存储canvas的基础属性
const state = reactive({
    width: 0,
    height: 0,
    hasDraw: false, // 用户是否有签名
    // signImage: '',
    flag: true,
    top: 0,
    left: 0
});
const startX = ref(0); // 第一点的 x 坐标
const startY = ref(0); // 第一点的 y 坐标
const endX = ref(0); // 第二点的 x 坐标
const endY = ref(0); // 第二点的 y 坐标

// 1.  页面构建完成之后,初始化数据
onMounted(() => {
    state.hasDraw = false;
    // 确保 canvas 节点已渲染完毕
    setTimeout(() => {
        init();
    }, 500);
});
// 2. 初始化方法
const init = () => {
    // 因为在taro中 Taro.createSelectorQuery().select("**") 获取不到节点,就使用document获取
    const canvasNode = document.querySelector('#canvasSign')?.childNodes[0] || {};
    // 在 taro中 canvas被包裹了一层节点 <taro-canvas-core></taro-canvas-core>,所以读取 canvasSign 的childNodes
    const parentNode = document.querySelector('#canvas-content') || {};
    // 根据父节点设置 canvas 的宽高     !!!!
    canvasNode.width = parentNode?.clientWidth;
    canvasNode.height = parentNode?.clientHeight;

    // 用于清空签名
    state.width = canvasNode.width;
    state.height = canvasNode.height;

    content = canvasNode.getContext('2d');

    state.top = 10; // 根据情况设置 上下左右 初始偏移量 !!!在移动端没有获取到offsetX和offsetY,这里需要推算一下自己页面的偏移量
    state.left = 20;
};
// 落笔: 开始签名
const startEventHandler = event => {
    event.preventDefault();

    let target = event.targetTouches?.[0] || {}; // 获取去点击的元素以及位置信息

    startX.value = target.pageX - state.left; // x 偏移量 - x方向的 padding
    startY.value = target.pageY - state.top;

    // 开始签名时,更新签名结束的点位信息
    endX.value = startX.value;
    endY.value = startY.value;
    // 描点连线
    draw();
};

// 签名 ing
const moveEventHandler = e => {
    state.hasDraw = true; // 更新用户的绘画状态,用户判断用户是否签名

    e.preventDefault();
    endX.value = e.targetTouches[0].clientX - state.left;
    endY.value = e.targetTouches[0].clientY - state.top;
    draw();
    // 绘画连线之后需要更新结束的点位信息,每一次都是从上一次的最后一个点开始的
    // 所以 startX startY 直接取 endX endY
    startX.value = endX.value;
    startY.value = endY.value;
};

// 停止签名
const endEventHandler = e => {
    e.preventDefault();
};

// 起笔: 签名结束
const leaveEventHandler = event => {
    event.preventDefault();
};

清空画布

// 清空画布
const clearClick = () => {
    content.clearRect(0, 0, state.width, state.height);
    state.hasDraw = false;
};

保存签名

// 保存签名
const saveClick = () => {
    console.log('state.flag ', state.flag);
    if (state.hasDraw) {
        setTimeout(() => {
            Taro.canvasToTempFilePath({
                canvasId: 'canvasSign',
                fileType: 'png',
                success: res => {
                    emit('confirm', res.tempFilePath);
                },
                fail(error) {
                    console.log(error);
                }
            });
        }, 200);
    } else {
        Taro.showToast({
            icon: 'none',
            title: '未进行签名!不能保存'
        });
    }
};

注意

在实现签名时可能会有的几个问题:

  1. 签名位置不准确有偏移
  2. 签名的画笔比较模糊,有马赛克

问题1:签名位置不准确有偏移
原因: 有位置的偏移是因为点的位置计算不正确,需要扣除上下左右的间距;因为水平和垂直的偏移都取的target的clientX和clientY的是,那就是包含了上下左右的间距,扣除上下左右的内外间距就行了

  startX.value = target.pageX - state.left; // x 偏移量 - x方向的 padding/offsetX
  startY.value = target.pageY - state.top;

问题2: 签名的画笔比较模糊,有马赛克
原因:
canvas dom节点的宽高和实际canvas加载的宽高不一致导致;在给canvas设置宽高的时候直接在dom节点上设置的/通过style设置宽高都是不准确的,需要这样设置才能保证canvas的宽高设置正确

    const canvasNode = document.querySelector('#canvasSign')?.childNodes[0] || {};
    // 在 taro中 canvas被包裹了一层节点 <taro-canvas-core></taro-canvas-core>,所以读取 canvasSign 的childNodes
    const parentNode = document.querySelector('#canvas-content') || {};
    // 根据父节点设置 canvas 的宽高     !!!!
    canvasNode.width = parentNode?.clientWidth;
    canvasNode.height = parentNode?.clientHeight;

排查方法
可以看canvas元素的宽高和实际canvas的宽高是否一致判断

完整组件地址完整代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

加解密与HTTPS(3)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 除了对称加密算法和非对称加密算法&#xff0c;再就是最后的一种加密算法了&#xff1a;不可逆加密算法。 对称加密算法和非对称加密算法在处理明文的过程中需要…

线程池ThreadPoolExecutor的源码中是如何解决并发问题的?

ThreadPoolExecutor面临哪些线程安全问题 ThreadPoolExecutor俗称线程池&#xff0c;作为java.util.concurrent包对外提供基础实现&#xff0c;以内部线程池的形式对外提供管理任务执行&#xff0c;线程调度&#xff0c;线程池管理等等服务。 然而为高效并发而生ThreadPoolExe…

C++项目实战:职工管理系统

1.管理系统的要求 系统可以管理公司内部所有员工的信息 主要使用c实现一个基于多态的职工管理系统 公司中的职工分为三类&#xff1a;普通员工、经理、老板&#xff0c;显示信息时需要显示职工编号、职工姓名、职工岗位以及职责 普通员工职责&#xff1a;完成经理安排的各项任…

oh my 毕设-人体姿态估计综述

文章目录What is Human Pose Estimation?Classical vs. Deep Learning-based approachesClassical approaches to 2D Human Pose EstimationDeep Learning-based approaches to 2D Human Pose EstimationHuman Pose Estimation using Deep Neural NetworksOpenPoseAlphaPose (…

想要努力赚钱,培养四种基础能力

这四种基础能力分别是&#xff1a;认知力、学习力、执行力、复盘力。我们的认知和思维&#xff0c;很大程度上&#xff0c;都是由所处的环境和圈子决定的。在同一个环境和圈子里面呆久了&#xff0c;你的认知就会被固化了。穷人最根本的枷锁&#xff0c;不是缺乏资金&#xff0…

excel图表技巧:看看,这个饼图象不象罗盘?

说到制作柱形图、条形图、饼图&#xff0c;相信大家都没有问题&#xff0c;直接选中数据&#xff0c;再插入对应的图表就行了&#xff0c;可如果要制作一张双层饼图你还会吗&#xff1f;“啥&#xff1f;还有双层饼图&#xff1f;”嘿嘿&#xff0c;不知道了吧&#xff0c;双层…

PVE+NUT+群晖等配置

文章目录配置文件说明默认配置(翻译的)ups.conf(设置ups通信相关)upsd.conf(设置ups客户访问的相关信息)upsd.users(设置upsd用户)nut.conf(nut的配置,主要是模式&#xff0c;决定使用哪些文件)upsmon.confupssched.confupssched-cmd官方手册写的可以的文章只需要实现&#xff…

excel数据查找:内容查找统计的函数公式

判断单元格是否包含特定内容是平时工作中经常会遇到的一类问题&#xff0c;常见于包含备注信息的表格中。例如下面这个考勤汇总表&#xff0c;需要根据备注中的内容判断该员工是否存在加班的情况&#xff0c;就属于这类问题。 遇到这类问题该如何处理&#xff0c;常用的公式做法…

klee2.3 教程1-2

1. klee2.3 安装 system&#xff1a;unbuntu 20.04 note: llvm-13klee2.3z3-4.10 1.1 install dependencies KLEE 需要 LLVM 的所有依赖项&#xff08;请参阅此处&#xff09;&#xff0c;以及更多。特别是&#xff0c;您应该安装下面列出的程序和库。graphviz/doxygen是可…

初级C语言之【操作符】

&#x1f996;作者&#xff1a;学写代码的恐龙 &#x1f996;博客主页&#xff1a;学写代码的恐龙博客主页 &#x1f996;专栏&#xff1a;【初级c语言】 &#x1f996;语录&#xff1a;❀未来的你&#xff0c;一定会感谢现在努力奋斗的自己❀ 初级C语言之【操作符详解】一&am…

综合能源系统分析的统一能路理论(三):《稳态与动态潮流计算》(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

spring6笔记3(bean的循环依赖,手写spring框架,ioc注解开发,JdbcTemplate)

第九章、Bean的循环依赖问题 9.1 什么是Bean的循环依赖 A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你&#xff0c;你也依赖我。 比如&#xff1a;丈夫类Husband&#xff0c;妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。 public class Husband…

【java线程池详解】

java线程池详解线程的基本状态Executor框架Executor框架组成部分Executor框架使用示意图Runnable接口、Callable接口ExecutorsFuture接口和实现Future接口的FutureTask类Future和FutureTask的关系ThreadPoolExecutor类ThreadPoolExecutor 饱和策略&#xff08;拒绝策略&#xf…

MySQL去重,一条SQL语句完美解决【去重留一】

此处以某消费记录表(consume_record)为例&#xff0c;SQL语句如下&#xff1a; DELETE consume_record FROM consume_record, ( SELECT min(id) id, user_id, monetary, con…

Qt第五十五章:Qt Design Studio设计登录页并打包到python运行

目录 一、Qt Design Studio 二、导出所有文件到QRC&#xff08;不要改动默认的QRC文件名称&#xff09; 三、QRC转换成py 1.删除Constants.qml中的 2.将App.qml和Screen01.qml中的 3.转换 4、将QRC文件和转换后的py文件&#xff0c;复制到python项目中使用。 一、Qt Des…

【云原生 Kubernetes】k8s集群部署springboot项目

一、前言 本篇&#xff0c;我们将基于k8s集群&#xff0c;模拟一个比较接近实际业务的使用场景&#xff0c;使用k8s集群部署一个springboot的项目&#xff0c;我们的需求是&#xff1a; 部署SpringBoot项目到阿里云服务器 &#xff1b;基于容器打包&#xff0c;推送私有镜像仓…

Presto 之 BTreeIndex 索引代码走读

一. 前言 本文主要介绍在Presto&#xff08;OpenLookeng&#xff09;中的BTree索引的代码实现。关于BTree索引原理的介绍可以参考官网资料openLooKeng documentation。 二. BTreeIndex 索引建立 在Presto中&#xff0c;BTreeIndex 索引是通过mapdb中的BTreeMap数据结构实现的&a…

【java入门系列一】java基础

学习记录&#x1f914;写在前面JDK\JREPython有没有虚拟机&#xff1f;第一个code规范学习方法转义符号注释讨论总结谢谢点赞交流&#xff01;(❁◡❁)更多代码&#xff1a; Gitee主页&#xff1a;https://gitee.com/GZHzzz博客主页&#xff1a; CSDN&#xff1a;https://blog.…

13---SpringBoot整合JWT,实现登录和拦截

1、 JWT简介 什么是JWT&#xff1f; JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。它将用户信息加密到token里&#xff0c;服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性&#xff0c;只要正确即通过验证&…

在Ubuntu上安装Azure DevOps代理程序

Contents1 概述2. 安装Ubuntu 18.04操作系统3. 安装Azure DevOps Server 代理3.1 安装Azure DevOps Server 代理3.2 以服务方式运行代理1. 概述Ubuntu是一个以桌面应用为主的Linux操作系统&#xff0c;目前在不适用微软Windows的企业中&#xff0c;ubuntu被广泛应用在个人电脑中…