资讯详情

不翻转屏幕的情况下,uniapp实现横屏签名(强制竖屏)

📅 2026/10/31 1:29:54 | 华诺云谱 👁 阅读
不翻转屏幕的情况下,uniapp实现横屏签名(强制竖屏)
不翻转屏幕的情况下uniapp实现横屏签名签名页面需强制竖屏否则有些用户手机锁屏未开时会导致页面翻转。强制竖屏//单页面强制 { path: , style: { navigationBarTitleText: , pageOrientation: portrait // 强制竖屏 } }, //全页面强制 globalStyle: { pageOrientation: portrait // 强制竖屏 },封装签名组件cat-signature.vuetemplate view view v-ifvisibleSync classcat-signature :class{ visible: show } touchmove.stop.preventmoveHandle view classmask/view view classcontent view styleposition: relative; canvas classfirstCanvas :canvas-idcanvasId nameautograph touchmovemove touchstartstart($event) touchendend touchcancelcancel longtaptap disable-scrolltrue errorerror / !-- 用于旋转输出的隐藏 canvas给一个足够大的固定尺寸 避免动态尺寸在某些端上 canvasToTempFilePath 取不到内容 -- canvas classrotateCanvas :canvas-idcanvasId _rotate / view classtipsClas flexW v-if!hasDh text签/text text字/text text区/text /view /view /view view classbtnClas view classbtns view classbtn flexHA tapclose text classtopText取/text text classbottomText消/text /view view classbtn closeBtn flexHA tapclear text classtopText重/text text classbottomText签/text /view view classbtn _save flexHA tapsave text classtopText保/text text classbottomText存/text /view /view /view /view view classtipsClas tipsOutsideClas flexW v-iftipShow text请/textnbsp; text先/textnbsp; text签/textnbsp; text名/text /view /view /template script let content null; let touchs []; let canvasw 0; let canvash 0; // 笔迹边界用于导出时裁掉多余白边 let ink null; function resetInk() { ink { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity, has: false }; } resetInk(); //获取系统信息 uni.getSystemInfo({ success: function(res) { //重签清除画布的宽高 canvasw res.windowWidth*0.84; canvash res.windowHeight } }); export default { name: CatSignature, props: { visible: { type: Boolean, default: false }, canvasId: { type: String, default: firstCanvas } }, data() { return { show: false, visibleSync: false, signImage: , hasDh: false, tipShow:false, timer:null, countdown:2 }; }, watch: { visible(val) { this.visibleSync val; this.show val; // 打开时重置笔迹边界 if (val) resetInk(); this.getInfo(); } }, created(options) { this.visibleSync this.visible; this.getInfo(); setTimeout(() { this.show this.visible; }, 100); }, methods: { getInfo() { //获得Canvas的上下文 content uni.createCanvasContext(this.canvasId, this); //设置线的颜色 content.setStrokeStyle(#000); //设置线的宽度 content.setLineWidth(3); //设置线两端端点样式更加圆润 content.setLineCap(round); //设置两条线连接处更加圆润 content.setLineJoin(round); }, // close() { this.show false; this.hasDh false; this.$emit(close); }, moveHandle() {}, // 更新笔迹边界 updateInk(point) { if (!ink.has) { ink.minX ink.maxX point.x; ink.minY ink.maxY point.y; ink.has true; } else { if (point.x ink.minX) ink.minX point.x; if (point.x ink.maxX) ink.maxX point.x; if (point.y ink.minY) ink.minY point.y; if (point.y ink.maxY) ink.maxY point.y; } }, // 画布的触摸移动开始手势响应 start(e) { let point { x: e.touches[0].x, y: e.touches[0].y }; touchs.push(point); this.updateInk(point); this.hasDh true; }, // 画布的触摸移动手势响应 move: function(e) { let point { x: e.touches[0].x, y: e.touches[0].y }; touchs.push(point); this.updateInk(point); if (touchs.length 2) { this.draw(touchs); } }, // 画布的触摸移动结束手势响应 end: function(e) { //清空轨迹数组 for (let i 0; i touchs.length; i) { touchs.pop(); } }, // 画布的触摸取消响应 cancel: function(e) { // console.log(触摸取消 e) }, // 画布的长按手势响应 tap: function(e) { // console.log(长按手势 e) }, error: function(e) { // console.log(画布触摸错误 e) }, //绘制 draw: function(touchs) { let point1 touchs[0]; let point2 touchs[1]; content.moveTo(point1.x, point1.y); content.lineTo(point2.x, point2.y); content.stroke(); content.draw(true); touchs.shift(); }, //清除操作 clear: function() { //清除画布 content.clearRect(0, 0, canvasw, canvash); content.draw(true); resetInk(); this.hasDh false; this.$emit(clear); }, save() { let that this; if (!this.hasDh) { this.tipShowtrue; this.timersetInterval(() { if(this.countdown0) { this.countdown--; }else { clearInterval(this.timer); this.timernull; this.countdown2; this.tipShowfalse; } },1000) return; } uni.showLoading({ mask: true }); // 只导出笔迹所在区域避免整屏白边 const pad 16; // 四周留一点白边避免笔画贴边 let x 0, y 0, cw canvasw, ch canvash; if (ink ink.has) { x Math.max(0, ink.minX - pad); y Math.max(0, ink.minY - pad); cw Math.min(canvasw, ink.maxX pad) - x; ch Math.min(canvash, ink.maxY pad) - y; } if (cw 20) cw 20; if (ch 20) ch 20; const dpr uni.getSystemInfoSync().pixelRatio || 2; setTimeout(() { // 1. 裁出笔迹区域导出为临时图片 uni.canvasToTempFilePath({ canvasId: this.canvasId, x: x, y: y, width: cw, height: ch, destWidth: cw * dpr, destHeight: ch * dpr, success: function(res) { // 2. 把图片旋转 90° 画到隐藏 canvas输出横向图片 that.exportRotated(res.tempFilePath); }, fail: function(err) { console.log(err); uni.hideLoading(); } }, this ); }, 100); }, // 把裁剪后的签字图输出为横向图片竖着写的旋转 90°本来就横着的只裁白边 exportRotated(srcPath) { let that this; uni.getImageInfo({ src: srcPath, success(img) { const w img.width; const h img.height; // 隐藏 canvas 固定 800×800输出超限时等比缩小 const maxDim 780; const s Math.min(1, maxDim / Math.max(w, h)); const dw Math.round(w * s); const dh Math.round(h * s); // 笔迹明显高于宽说明用户是横握手机写的需要逆时针转 90° 变横向 // 否则本来就是横向笔迹保持原方向 const needRotate h w * 1.15; const outW needRotate ? dh : dw; const outH needRotate ? dw : dh; const rctx uni.createCanvasContext(that.canvasId _rotate, that); // 白底避免透明背景在部分场景变黑 rctx.setFillStyle(#ffffff); rctx.fillRect(0, 0, outW, outH); if (needRotate) { // 用户视角的上是屏幕的右屏幕右侧要变成图片顶部 rctx.translate(0, dw); rctx.rotate(-Math.PI / 2); } rctx.drawImage(srcPath, 0, 0, dw, dh); rctx.draw(false, () { setTimeout(() { uni.canvasToTempFilePath({ canvasId: that.canvasId _rotate, x: 0, y: 0, width: outW, height: outH, destWidth: outW, destHeight: outH, success(r2) { uni.hideLoading(); that.signImage r2.tempFilePath; that.$emit(save, r2.tempFilePath); that.hasDh false; that.show false; }, fail(err) { console.log(rotate export fail, err); uni.hideLoading(); // 旋转失败兜底用裁剪后的原图保证至少能上传 that.signImage srcPath; that.$emit(save, srcPath); that.hasDh false; that.show false; } }, that ); }, 150); }); }, fail(err) { console.log(getImageInfo fail, err); uni.hideLoading(); // 兜底旋转失败用裁剪后的原图 that.signImage srcPath; that.$emit(save, srcPath); that.hasDh false; that.show false; } }); } } }; /script style langscss .cat-signature.visible { visibility: visible; } .tipsClas { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(90deg); font-size: 100rpx; margin: auto; color: #888; z-index: 99; text { margin: 0 60rpx; } } .tipsOutsideClas { font-size: 30rpx; background: #333; color: #fff; padding:20rpx 30rpx; border-radius: 8rpx; transform: translate(-50%, -45%) rotate(90deg); text { margin: 0; } } .cat-signature { display: block; position: fixed; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; z-index: 11; height: 100vh; visibility: hidden; .mask { display: block; opacity: 0; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #fff; } .content { display: block; position: absolute; top:0; right: 0; width: 84%; z-index: 9; .firstCanvas { background-color: #fff; width: 100%; height: 100vh; } // 旋转输出的隐藏 canvas不能用 display:none否则 uni.canvasToTempFilePath 取不到内容。 // 固定 800×800导出时按实际需要的区域裁剪。 .rotateCanvas { position: absolute; left: -9999px; top: -9999px; width: 800px; height: 800px; background-color: #fff; } } } .btnClas { position: absolute; left: 0; top: 0; border-right:1rpx solid #eeeeee;; z-index: 9; .btns { background: #fff; border-radius:0 0 10rpx 10rpx; justify-content: space-around; padding:0 27rpx; position: relative; display: flex; height: 100vh; flex-direction: column; z-index: 99; .btn { width: 68rpx; text-align: center; font-size: 30rpx; height: 240rpx; line-height: 240rpx; background-color: #999; color: #fff; border-radius: 6rpx; position: relative; text { transform: rotate(90deg); position: absolute; } .topText { bottom: 30rpx; } .bottomText { top: 30rpx; } } .closeBtn { background-color: #f9ae3d; } ._save { background-color: rgb(67, 117, 255); } } } .visible .mask { display: block; opacity: 1; } /style页面使用调用catSignature canvasIdmycanvas closecloseSignature savesaveSignature :visiblesignatureShow / import catSignature from /pagesA/components/cat-signature.vue; components: { catSignature }, data() { return { signatureShow:false//签名弹窗 }; }, // 取消签名 closeSignature() { this.signatureShow false; }, // 确认签名 saveSignature(e) { this.signatureShow false; if(e) { uni.showLoading({ // title: 上传中, mask: true }); let that this; uni.uploadFile({ url: url,//上传接口 filePath: e, header: { Authorization: token }, name: file, fileType: image, success: (uploadFileRes) { let imgData JSON.parse(uploadFileRes.data);//后端返回的图片直接使用即可 } }); }else { this.$u.toast(签名失败) } },
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑