网站教程制作,优化方案物理电子版,中山 环保 骏域网站建设专家,怎么开发直播平台前言#xff1a;H5时常需要给C端用户签名的功能#xff0c;以下是基于Taro框架开发的H5页面实现
一、用到的技术库
签字库#xff1a;react-signature-canvas主流React Hooks 库#xff1a;ahooks
二、组件具体实现
解决H5样式问题#xff0c;主要还是通过两套样式实现…前言H5时常需要给C端用户签名的功能以下是基于Taro框架开发的H5页面实现
一、用到的技术库
签字库react-signature-canvas主流React Hooks 库ahooks
二、组件具体实现
解决H5样式问题主要还是通过两套样式实现横屏和竖屏的处理
index.tsx
import { useState, useRef, useCallback, useEffect, useMemo } from react;
import Taro from tarojs/taro;
import SignatureCanvas from react-signature-canvas;
import { useSize } from ahooks;
import { View } from tarojs/components;
import { rotateImg } from ./utils;
import ./index.less;interface IProps {visible: boolean;setVisible: (e) void;signText?: string;onChange?: (e?) void; // 生成的图片onSure: (e?) void; // 确定的回调
}
// 签字版组件
const SignatureBoard (props: IProps) {const { visible, setVisible, signText 请在此空白处签下您的姓名, onChange, onSure } props;const [signTip, setSignTip] useState(signText);const sigCanvasRef useRefSignatureCanvas | null(null);const canvasContainer useRefHTMLElement(null);const compContainer useRefHTMLElement(null);const compSize useSize(compContainer);const canvasSize useSize(canvasContainer);const [isLandscape, setIsLandscape] useStateboolean(false); // 是否横屏// 提示的文字数组为了在竖屏的情况下每个字样式旋转const tipText useMemo(() {return signTip?.split() || [];}, [signTip]);// 重签const clearSign useCallback(() {setSignTip(signText);sigCanvasRef?.current?.clear();}, [signText]);// 取消const cancelSign useCallback(() {clearSign();setVisible?.(false);}, [clearSign, setVisible]);// 确定const sureSign useCallback(() {const pointGroupArray sigCanvasRef?.current?.toData();if (pointGroupArray.flat().length 30) {Taro.showToast({ title: 请使用正楷字签名, icon: none });return;}if (isLandscape) {// 横屏不旋转图片onSure?.(sigCanvasRef.current.toDataURL());} else {rotateImg(sigCanvasRef?.current?.toDataURL(), result onSure?.(result), 270);}setVisible?.(false);}, [isLandscape, onSure, setVisible]);// 由于 onorientationchange 只能判断自动旋转无法判断手动旋转因此不选择监听 orientationchange// 监听 resize 可以实现比较宽高即可判断是否横屏即宽大于高就是横屏状态与下面为了方便使用 ahooks 的 useSize 思想一致useEffect(() {// 如果宽度大于高度就表示是在横屏状态if ((compSize?.width ?? 0) (compSize?.height ?? 1)) {// console.log(横屏状态);setIsLandscape(true);clearSign();} else {// console.log(竖屏状态);setIsLandscape(false);clearSign();}}, [clearSign, compSize?.height, compSize?.width]);if (!visible) return null;return (View ref{compContainer} classNamesignature-board-comp onClick{e e.stopPropagation()}View classNamesign-board-btnsView classNameboard-btn onClick{cancelSign}View classNameboard-btn-text取消/View/ViewView classNameboard-btn onClick{clearSign}View classNameboard-btn-text重签/View/ViewView classNameboard-btn confirm-btn onClick{sureSign}View classNameboard-btn-text确定/View/View/ViewView classNamesign-board ref{canvasContainer}SignatureCanvaspenColor#000 // 笔刷颜色minWidth{1} // 笔刷粗细maxWidth{1}canvasProps{{id: sigCanvas,width: canvasSize?.width,height: canvasSize?.height, // 画布尺寸className: sigCanvas}}ref{sigCanvasRef}onBegin{() setSignTip()}onEnd{() {onChange?.(sigCanvasRef?.current?.toDataURL());}}/{signTip (div classNameSignatureTips{tipText tipText?.map((item, index) (View key{${index.toString()}} classNametip-text{item}/View))}/div)}/View/View);
};export default SignatureBoard;inde.less
media screen and (orientation: portrait) {/*竖屏 css*/.signature-board-comp {position: fixed;top: 0;right: 0;bottom: 0;left: 0;z-index: 9;display: flex;flex-wrap: nowrap;align-items: stretch;box-sizing: border-box;width: 100vw;height: 100vh;padding: 48px 52px 48px 0px;background-color: #ffffff;.sign-board-btns {display: flex;flex-direction: column;flex-wrap: nowrap;align-items: center;justify-content: flex-end;box-sizing: border-box;width: 142px;padding: 0px 24px;.board-btn {display: flex;align-items: center;justify-content: center;width: 96px;height: 312px;margin-top: 32px;border: 1px solid #181916;border-radius: 8px;opacity: 1;:active {opacity: 0.9;}.board-btn-text {color: #181916;font-size: 30px;transform: rotate(90deg);}}.confirm-btn {color: #ffffff;background: #181916;.board-btn-text {color: #ffffff;}}}.sign-board {position: relative;flex: 1;.sigCanvas {width: 100%;height: 100%;background: #f7f7f7;border-radius: 10px;}.SignatureTips {position: absolute;top: 0;left: 50%;display: flex;flex-direction: column;align-items: center;justify-content: center;width: 50px;height: 100%;color: #a2a0a8;font-size: 46px;transform: translateX(-50%);pointer-events: none;.tip-text {line-height: 50px;transform: rotate(90deg);}}}}
}media screen and (orientation: landscape) {/*横屏 css*/.signature-board-comp {position: fixed;top: 0;right: 0;bottom: 0;left: 0;z-index: 9;display: flex;flex-direction: column-reverse;flex-wrap: nowrap;box-sizing: border-box;width: 100vw;height: 100vh;padding: 0px 48px 0px 48px;background-color: #ffffff;.sign-board-btns {display: flex;flex-wrap: nowrap;flex-wrap: nowrap;align-items: center;justify-content: flex-end;box-sizing: border-box;width: 100%;height: 20vh;padding: 12px 0px;.board-btn {display: flex;align-items: center;justify-content: center;width: 156px;height: 100%;max-height: 48px;margin-left: 16px;border: 1px solid #181916;border-radius: 4px;opacity: 1;:active {opacity: 0.9;}.board-btn-text {color: #181916;font-size: 15px;}}.confirm-btn {color: #ffffff;background: #181916;.board-btn-text {color: #ffffff;}}}.sign-board {position: relative;flex: 1;box-sizing: border-box;height: 80vh;.sigCanvas {box-sizing: border-box;width: 100%;height: 80vh;background: #f7f7f7;border-radius: 5px;}.SignatureTips {position: absolute;top: 0;left: 0;display: flex;align-items: center;justify-content: center;box-sizing: border-box;width: 100%;height: 100%;color: #a2a0a8;font-size: 23px;pointer-events: none;}}}
}utils.ts
// canvas绘制图片旋转270度
export const rotateImg (src, callback, deg 270) {const canvas document.createElement(canvas);const ctx canvas.getContext(2d);const image new Image();image.crossOrigin anonymous;image.src src;image.onload function () {const imgW image.width; // 图片宽度const imgH image.height; // 图片高度const size imgW imgH ? imgW : imgH; // canvas初始大小canvas.width size * 2;canvas.height size * 2;// 裁剪坐标const cutCoor {sx: size,sy: size - imgW,ex: size imgH,ey: size imgW};ctx?.translate(size, size);ctx?.rotate((deg * Math.PI) / 180);// drawImage向画布上绘制图片ctx?.drawImage(image, 0, 0);// getImageData() 复制画布上指定矩形的像素数据const imgData ctx?.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey);canvas.width imgH;canvas.height imgW;// putImageData() 将图像数据放回画布ctx?.putImageData(imgData as any, 0, 0);callback(canvas.toDataURL());};
};