在移动端签名场景中,竖屏状态下签名区域宽度不足,容易导致签名内容挤压、书写不顺畅,为签名面板添加横屏提示背景是解决该问题的有效方案,可在用户竖屏进入签名页时主动引导横屏操作。

实现核心思路
整个功能的实现主要分为三个部分:首先是检测当前设备的屏幕方向,判断是否为竖屏状态;其次是在竖屏状态下显示横屏提示背景,隐藏签名面板主体;最后是监听屏幕方向变化,当切换为横屏时隐藏提示背景,展示可操作的签名面板。
屏幕方向检测方案
可以通过window.matchMedia方法监听屏幕方向变化,该方法兼容性较好,支持主流移动端浏览器。同时需要结合screen.orientation属性获取当前屏幕方向状态,更精准地判断横竖屏切换。
提示背景设计要点
横屏提示背景需要覆盖整个签名区域,内容要简洁明确,通常包含旋转手机的图标提示和文字说明,避免复杂设计影响用户理解。提示背景的层级要高于签名面板,确保竖屏时不会被签名内容遮挡。
完整实现代码示例
HTML结构
页面结构包含签名面板容器、横屏提示层、Canvas签名区域三个部分,结构如下:
<div class="signature-container">
<!-- 横屏提示背景 -->
<div class="landscape-tip" id="landscapeTip">
<div class="tip-content">
<div class="rotate-icon">↻</div>
<p>请将手机横屏以获得更好的签名体验</p>
</div>
</div>
<!-- 签名面板主体 -->
<div class="signature-main" id="signatureMain">
<canvas id="signatureCanvas">您的浏览器不支持Canvas,请升级浏览器</canvas>
<div class="signature-actions">
<button id="clearBtn">清除</button>
<button id="confirmBtn">确认</button>
</div>
</div>
</div>
CSS样式
样式部分需要设置签名容器的相对定位,提示层和签名主体绝对定位覆盖容器,同时设计提示层的居中布局和旋转图标样式:
.signature-container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.landscape-tip {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
color: #fff;
}
.tip-content {
text-align: center;
}
.rotate-icon {
font-size: 60px;
margin-bottom: 20px;
animation: rotate 2s infinite linear;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.signature-main {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
flex-direction: column;
}
#signatureCanvas {
flex: 1;
width: 100%;
background-color: #fff;
border-bottom: 1px solid #eee;
}
.signature-actions {
padding: 15px;
display: flex;
justify-content: space-around;
}
.signature-actions button {
padding: 10px 30px;
border: none;
border-radius: 4px;
background-color: #007bff;
color: #fff;
font-size: 16px;
}
JavaScript逻辑
逻辑部分实现屏幕方向检测、横竖屏切换时的显示隐藏控制,同时包含基础的Canvas签名功能实现:
// 获取DOM元素
const landscapeTip = document.getElementById('landscapeTip');
const signatureMain = document.getElementById('signatureMain');
const canvas = document.getElementById('signatureCanvas');
const clearBtn = document.getElementById('clearBtn');
const confirmBtn = document.getElementById('confirmBtn');
const ctx = canvas.getContext('2d');
// 初始化Canvas尺寸
function initCanvasSize() {
const container = canvas.parentElement;
canvas.width = container.clientWidth;
canvas.height = container.clientHeight - 60; // 减去操作栏高度
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.lineCap = 'round';
}
// 判断是否为竖屏
function isPortrait() {
// 优先使用screen.orientation属性
if (window.screen.orientation) {
return window.screen.orientation.type.includes('portrait');
}
// 兼容旧浏览器
return window.innerHeight > window.innerWidth;
}
// 切换横竖屏显示状态
function toggleDisplay() {
if (isPortrait()) {
// 竖屏显示提示,隐藏签名面板
landscapeTip.style.display = 'flex';
signatureMain.style.display = 'none';
} else {
// 横屏隐藏提示,显示签名面板
landscapeTip.style.display = 'none';
signatureMain.style.display = 'flex';
// 横屏后重新初始化Canvas尺寸
setTimeout(initCanvasSize, 100);
}
}
// 监听屏幕方向变化
if (window.screen.orientation) {
window.screen.orientation.addEventListener('change', toggleDisplay);
} else {
// 兼容不支持screen.orientation的浏览器,监听窗口尺寸变化
window.addEventListener('resize', toggleDisplay);
}
// 初始化执行一次状态判断
toggleDisplay();
// Canvas签名功能实现
let isDrawing = false;
let lastX = 0;
let lastY = 0;
// 开始绘制
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
});
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
isDrawing = true;
const touch = e.touches[0];
const rect = canvas.getBoundingClientRect();
[lastX, lastY] = [touch.clientX - rect.left, touch.clientY - rect.top];
});
// 绘制过程
canvas.addEventListener('mousemove', (e) => {
if (!isDrawing) return;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
if (!isDrawing) return;
const touch = e.touches[0];
const rect = canvas.getBoundingClientRect();
const currentX = touch.clientX - rect.left;
const currentY = touch.clientY - rect.top;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(currentX, currentY);
ctx.stroke();
[lastX, lastY] = [currentX, currentY];
});
// 结束绘制
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseleave', () => isDrawing = false);
canvas.addEventListener('touchend', () => isDrawing = false);
// 清除签名
clearBtn.addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
// 确认签名
confirmBtn.addEventListener('click', () => {
const signatureData = canvas.toDataURL('image/png');
console.log('签名数据:', signatureData);
alert('签名已确认,数据已生成');
});
注意事项
- 部分浏览器对
screen.orientation的支持存在差异,建议同时添加窗口resize监听作为兼容方案。 - 横屏提示的动画效果不宜过于复杂,避免占用过多性能,影响页面加载速度。
- Canvas签名功能需要同时兼容鼠标事件和触摸事件,确保PC端和移动端都能正常使用。
- 如果签名面板需要嵌入到iframe中,需要额外处理iframe内的屏幕方向检测逻辑,避免检测失效。