该 HTML 文件是一个功能完整、跨设备兼容的在线电子签名工具,基于 HTML5 Canvas 实现签名绘制核心功能,搭配直观的样式控制(颜色、线条粗细)与操作按钮(清除、保存、下载),同时支持鼠标与触摸屏交互,整体设计简洁易用且视觉友好。
大家复制代码时,可能会因格式转换出现错乱,导致样式失效。建议先少量复制代码进行测试,若未能解决问题,私信回复源码两字,我会发送完整的压缩包给你。
演示效果


HTML&CSS
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>在线电子签名工具</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.container {
max-width: 800px;
width: 100%;
background: white;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
padding: 30px;
margin-top: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
}
h1 {
color: #2c3e50;
margin-bottom: 10px;
font-size: 2.2rem;
}
.subtitle {
color: #7f8c8d;
font-size: 1.1rem;
}
.signature-area {
border: 2px dashed #bdc3c7;
border-radius: 10px;
margin-bottom: 25px;
position: relative;
background-color: #f9f9f9;
overflow: hidden;
}
#signatureCanvas {
width: 100%;
height: 300px;
display: block;
cursor: crosshair;
background-color: white;
}
.canvas-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
color: #95a5a6;
font-size: 1.2rem;
pointer-events: none;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-bottom: 25px;
}
.btn {
padding: 12px 20px;
border: none;
border-radius: 6px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.btn-clear {
background-color: #e74c3c;
color: white;
}
.btn-save {
background-color: #2ecc71;
color: white;
}
.btn-download {
background-color: #3498db;
color: white;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.btn:active {
transform: translateY(0);
}
.btn-clear:hover {
background-color: #c0392b;
}
.btn-save:hover {
background-color: #27ae60;
}
.btn-download:hover {
background-color: #2980b9;
}
.color-picker {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.color-option {
width: 30px;
height: 30px;
border-radius: 50%;
cursor: pointer;
border: 2px solid transparent;
transition: transform 0.2s;
}
.color-option:hover {
transform: scale(1.1);
}
.color-option.active {
border-color: #2c3e50;
transform: scale(1.1);
}
.line-width {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.line-width input {
width: 100%;
}
.signature-preview {
margin-top: 30px;
text-align: center;
}
.preview-title {
margin-bottom: 15px;
color: #2c3e50;
}
#signaturePreview {
max-width: 100%;
border: 1px solid #bdc3c7;
border-radius: 5px;
display: none;
}
footer {
margin-top: 30px;
text-align: center;
color: #7f8c8d;
font-size: 0.9rem;
}
@media (max-width: 600px) {
.container {
padding: 20px;
}
h1 {
font-size: 1.8rem;
}
.controls {
flex-direction: column;
}
.btn {
width: 100%;
}
}
.instructions {
background-color: #f8f9fa;
border-left: 4px solid #3498db;
padding: 15px;
margin-bottom: 25px;
border-radius: 0 8px 8px 0;
}
.instructions h3 {
color: #2c3e50;
margin-bottom: 10px;
}
.instructions ul {
padding-left: 20px;
}
.instructions li {
margin-bottom: 8px;
}
</style>
</head>
<body>
<header>
<h1>在线电子签名工具</h1>
<p class="subtitle">使用鼠标或触摸屏创建您的电子签名</p>
</header>
<div class="container">
<div class="instructions">
<h3>使用说明</h3>
<ul>
<li>在下方画布区域使用鼠标或手指(触摸屏设备)绘制您的签名</li>
<li>可以使用下方的颜色和线条粗细选项调整签名样式</li>
<li>完成后可以保存签名或下载为PNG图片</li>
<li>如需重新开始,请点击"清除签名"按钮</li>
</ul>
</div>
<div class="signature-area">
<canvas id="signatureCanvas"></canvas>
<div class="canvas-placeholder">请在此处绘制您的签名</div>
</div>
<div class="color-picker">
<span>选择颜色:</span>
<div class="color-option active" style="background-color: #000000;" data-color="#000000"></div>
<div class="color-option" style="background-color: #e74c3c;" data-color="#e74c3c"></div>
<div class="color-option" style="background-color: #3498db;" data-color="#3498db"></div>
<div class="color-option" style="background-color: #2ecc71;" data-color="#2ecc71"></div>
<div class="color-option" style="background-color: #f39c12;" data-color="#f39c12"></div>
</div>
<div class="line-width">
<span>线条粗细:</span>
<input type="range" id="lineWidth" min="1" max="10" value="2">
<span id="widthValue">2px</span>
</div>
<div class="controls">
<button class="btn btn-clear" id="clearBtn">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path
d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z" />
<path fill-rule="evenodd"
d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z" />
</svg>
清除签名
</button>
<button class="btn btn-save" id="saveBtn">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path
d="M2 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H9.5a1 1 0 0 0-1 1v7.293l2.646-2.647a.5.5 0 0 1 .708.708l-3.5 3.5a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L7.5 9.293V2a2 2 0 0 1 2-2H14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h2.5a.5.5 0 0 1 0 1H2z" />
</svg>
保存签名
</button>
<button class="btn btn-download" id="downloadBtn">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path
d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z" />
<path
d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z" />
</svg>
下载签名
</button>
</div>
<div class="signature-preview">
<h3 class="preview-title">签名预览</h3>
<img id="signaturePreview" alt="签名预览">
</div>
</div>
<footer>
<p>© 2023 在线电子签名工具 | 使用HTML5 Canvas和JavaScript构建</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function () {
// 获取Canvas元素和上下文
const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d');
const placeholder = document.querySelector('.canvas-placeholder');
// 获取控制元素
const clearBtn = document.getElementById('clearBtn');
const saveBtn = document.getElementById('saveBtn');
const downloadBtn = document.getElementById('downloadBtn');
const colorOptions = document.querySelectorAll('.color-option');
const lineWidthInput = document.getElementById('lineWidth');
const widthValue = document.getElementById('widthValue');
const signaturePreview = document.getElementById('signaturePreview');
// 设置Canvas尺寸
function resizeCanvas() {
const container = canvas.parentElement;
canvas.width = container.clientWidth;
canvas.height = 300;
// 重新绘制内容(如果有)
redrawSignature();
}
// 初始化变量
let isDrawing = false;
let lastX = 0;
let lastY = 0;
let currentColor = '#000000';
let currentLineWidth = 2;
let signatureData = [];
// 初始化Canvas
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 设置初始绘制样式
ctx.strokeStyle = currentColor;
ctx.lineWidth = currentLineWidth;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
// 颜色选择
colorOptions.forEach(option => {
option.addEventListener('click', function () {
// 移除所有active类
colorOptions.forEach(opt => opt.classList.remove('active'));
// 添加active类到当前选项
this.classList.add('active');
// 更新当前颜色
currentColor = this.getAttribute('data-color');
ctx.strokeStyle = currentColor;
});
});
// 线条粗细
lineWidthInput.addEventListener('input', function () {
currentLineWidth = this.value;
ctx.lineWidth = currentLineWidth;
widthValue.textContent = `${currentLineWidth}px`;
});
// 开始绘制
function startDrawing(e) {
isDrawing = true;
[lastX, lastY] = getCoordinates(e);
placeholder.style.display = 'none';
// 开始新的路径
signatureData.push([]);
}
// 绘制中
function draw(e) {
if (!isDrawing) return;
e.preventDefault();
const [x, y] = getCoordinates(e);
// 绘制到Canvas
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
// 保存绘制数据
signatureData[signatureData.length - 1].push({ x, y });
[lastX, lastY] = [x, y];
}
// 结束绘制
function stopDrawing() {
isDrawing = false;
}
// 获取坐标(兼容鼠标和触摸事件)
function getCoordinates(e) {
let x, y;
if (e.type.includes('touch')) {
x = e.touches[0].clientX - canvas.getBoundingClientRect().left;
y = e.touches[0].clientY - canvas.getBoundingClientRect().top;
} else {
x = e.offsetX;
y = e.offsetY;
}
return [x, y];
}
// 重新绘制签名(用于Canvas尺寸调整后)
function redrawSignature() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (signatureData.length === 0) {
placeholder.style.display = 'flex';
return;
}
ctx.beginPath();
signatureData.forEach(stroke => {
if (stroke.length > 0) {
ctx.moveTo(stroke[0].x, stroke[0].y);
for (let i = 1; i < stroke.length; i++) {
ctx.lineTo(stroke[i].x, stroke[i].y);
}
}
});
ctx.stroke();
}
// 清除签名
function clearSignature() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
signatureData = [];
placeholder.style.display = 'flex';
signaturePreview.style.display = 'none';
}
// 保存签名预览
function saveSignature() {
if (signatureData.length === 0) {
alert('请先绘制签名!');
return;
}
const dataURL = canvas.toDataURL('image/png');
signaturePreview.src = dataURL;
signaturePreview.style.display = 'block';
// 平滑滚动到预览区域
signaturePreview.scrollIntoView({ behavior: 'smooth' });
}
// 下载签名
function downloadSignature() {
if (signatureData.length === 0) {
alert('请先绘制签名!');
return;
}
const dataURL = canvas.toDataURL('image/png');
const link = document.createElement('a');
link.download = '电子签名.png';
link.href = dataURL;
link.click();
}
// 事件监听器
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
// 触摸事件支持
canvas.addEventListener('touchstart', startDrawing);
canvas.addEventListener('touchmove', draw);
canvas.addEventListener('touchend', stopDrawing);
clearBtn.addEventListener('click', clearSignature);
saveBtn.addEventListener('click', saveSignature);
downloadBtn.addEventListener('click', downloadSignature);
// 防止触摸设备上的滚动
canvas.addEventListener('touchmove', function (e) {
if (isDrawing) {
e.preventDefault();
}
}, { passive: false });
});
</script>
</body>
</html>
HTML
- container: 核心功能容器:包裹使用说明、签名画布、样式控制、操作按钮与预览区,集中承载工具功能
- instructions: 使用说明区:通过列表清晰告知用户操作步骤(绘制、调整样式、保存等),降低使用门槛
- signature-area: 签名绘制区:包含 Canvas 画布与占位提示,是工具的核心交互区域
- signatureCanvas:签名绘制核心:基于 HTML5 Canvas 实现手写签名功能,支持像素级绘制
- canvas-placeholder:画布占位提示:未绘制时显示 "请在此处绘制您的签名",引导用户操作,绘制后隐藏
- color-picker:颜色选择区:提供 5 种预设颜色(黑、红、蓝、绿、橙),支持点击切换签名颜色
- color-option:单个颜色选项:圆形色块,active 类标识当前选中颜色,data-color 存储颜色值
- line-width:线条粗细控制区:包含滑块输入框与数值显示,支持 1-10px 的粗细调节
- lineWidth:粗细调节滑块:min=1/max=10/value=2,实时同步线条粗细
- controls:操作按钮容器:横向排列 "清除""保存""下载" 三个核心功能按钮,方便用户操作
- btn:功能按钮:每个按钮绑定不同操作,内嵌 SVG 图标增强视觉辨识度(如 "清除" 对应垃圾桶图标)
- svg:按钮图标:使用内联 SVG 绘制功能图标(清除、保存、下载),无需外部图片资源,加载更快
- signature-preview:签名预览区:显示保存后的签名图片,提供可视化反馈,未保存时隐藏
- signaturePreview":预览图片容器:src 动态赋值为 Canvas 导出的图片数据,display 控制显示隐藏
CSS
-
container 功能容器:1. 尺寸:最大宽度 800px、100% 自适应宽度,确保大屏幕不拉伸、小屏幕全屏;2. 视觉:白色背景(white)、圆角 15px、阴影(0 10px 30px rgba(0,0,0,0.1)),模拟卡片效果,与渐变背景区分,突出功能区;3. 内边距:padding: 30px,确保内部元素不拥挤。
-
.header 头部信息区:1. 布局:text-align: center 使标题 / 副标题居中,margin-bottom: 30px 与下方功能区分隔;2. 文字:标题(h1)颜色深灰蓝(#2c3e50)、字号 2.2rem,副标题(.subtitle)颜色浅灰(#7f8c8d)、字号 1.1rem,层级分明。
-
.instructions 使用说明区:1. 视觉:浅灰背景(#f8f9fa)、左侧 4px 蓝色边框(#3498db)、圆角(0 8px 8px 0),与其他区域区分,引导用户注意;2. 内边距:padding: 15px,列表左 padding 20px,确保文字不贴边。
-
.signature-area 签名绘制区:1. 边框:2px 虚线(dashed #bdc3c7)、圆角 10px,明确绘制范围;2. 背景:浅灰(#f9f9f9),与 Canvas 白色背景区分;3. 定位:position: relative,为绝对定位的占位提示提供父容器;4. 溢出:overflow: hidden,防止 Canvas 内容超出容器。
-
#signatureCanvas 签名画布:1. 尺寸:宽度 100%、高度 300px,填满父容器;2. 交互:cursor: crosshair,鼠标悬停时显示 "十字准星",提示可绘制;3. 背景:白色(white),模拟纸质签名效果。
-
.canvas-placeholder 画布占位提示:1. 定位:absolute 覆盖整个 Canvas,top/left: 0、width/height: 100%;2. 布局:flex 居中显示文字,pointer-events: none 确保不遮挡 Canvas 交互;3. 文字:浅灰(#95a5a6)、字号 1.2rem,提示用户操作。
-
.color-picker/.line-width 样式控制区:1. 布局:display: flex+align-items: center 使标签与选项垂直居中,gap: 10px 分隔元素,margin-bottom: 20px 与其他区域分隔;2. 颜色选项(.color-option):圆形(border-radius: 50%)、30×30px 尺寸,active 类添加深灰边框(#2c3e50),明确选中状态。
-
.controls 操作按钮容器:1. 布局:display: flex+flex-wrap: wrap(支持换行)、gap: 15px,适配不同屏幕宽度;2. 响应式:小屏幕自动换行,确保按钮不溢出。
-
.btn 功能按钮:1. 基础样式:padding: 12px 20px、无边框、圆角 6px、字号 1rem,display: flex+align-items: center+gap: 8px 使图标与文字居中;2. 颜色区分:清除(红#e74c3c)、保存(绿#2ecc71)、下载(蓝#3498db),通过颜色暗示功能(红 = 删除、绿 = 保存、蓝 = 下载);3. 交互:transition: all 0.3s ease,hover 时上移 2px(translateY(-2px))+ 阴影,active 时复位,提供点击反馈。
-
.signature-preview 签名预览区:1. 布局:text-align: center 使预览图居中,margin-top: 30px 与操作区分隔;2. 预览图(#signaturePreview):max-width: 100%避免拉伸,边框(1px solid #bdc3c7)+ 圆角 5px,默认 display: none,保存后显示。
-
footer 页脚信息区:1. 布局:margin-top: 30px、text-align: center,颜色浅灰(#7f8c8d)、字号 0.9rem,不抢占视觉焦点;2. 内容:版权 + 技术栈说明,增强工具可信度。
JavaScript
- 初始化与元素获取
javascript
document.addEventListener('DOMContentLoaded', function () {
// 1. 获取Canvas与上下文(核心绘制对象)
const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d'); // 2D绘制上下文,用于绘制签名
const placeholder = document.querySelector('.canvas-placeholder');
// 2. 获取控制元素(样式控制、操作按钮、预览区)
const clearBtn = document.getElementById('clearBtn');
const saveBtn = document.getElementById('saveBtn');
const downloadBtn = document.getElementById('downloadBtn');
const colorOptions = document.querySelectorAll('.color-option');
const lineWidthInput = document.getElementById('lineWidth');
const widthValue = document.getElementById('widthValue');
const signaturePreview = document.getElementById('signaturePreview');
// 3. 初始化状态变量
let isDrawing = false; // 是否正在绘制(防止鼠标离开后继续绘制)
let lastX = 0, lastY = 0; // 上一个绘制点的坐标(用于连接线条)
let currentColor = '#000000'; // 默认签名颜色(黑色)
let currentLineWidth = 2; // 默认线条粗细(2px)
let signatureData = []; // 存储签名数据(用于Canvas resize后重新绘制)
});
- Canvas 尺寸适配(核心兼容逻辑)
解决窗口 resize 时 Canvas 内容丢失问题,通过保存绘制数据重新渲染:
javascript
function resizeCanvas() {
const container = canvas.parentElement;
// 1. 更新Canvas尺寸为父容器宽度(高度固定300px)
canvas.width = container.clientWidth;
canvas.height = 300;
// 2. 重新绘制签名(如果有数据)
redrawSignature();
}
// 重新绘制签名:遍历保存的绘制数据,还原签名
function redrawSignature() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
if (signatureData.length === 0) { // 无签名数据时显示占位提示
placeholder.style.display = 'flex';
return;
}
// 遍历每一段绘制路径(每段对应一次鼠标按下到抬起的绘制)
signatureData.forEach(stroke => {
if (stroke.length > 0) {
ctx.beginPath(); // 开始新路径
ctx.moveTo(stroke[0].x, stroke[0].y); // 移动到第一段的起点
// 连接后续所有点,还原线条
for (let i = 1; i < stroke.length; i++) {
ctx.lineTo(stroke[i].x, stroke[i].y);
}
}
});
ctx.stroke(); // 执行绘制
}
// 初始化时调用一次,窗口 resize 时重新适配
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
- 签名绘制逻辑(核心交互)
通过监听鼠标 / 触摸事件,实现 "按下 - 移动 - 抬起" 的完整绘制流程,兼容 PC 与移动端:
javascript
// 1. 初始化绘制样式:圆角线条(避免尖锐边缘)
ctx.strokeStyle = currentColor; // 线条颜色
ctx.lineWidth = currentLineWidth; // 线条粗细
ctx.lineJoin = 'round'; // 线条连接点圆角
ctx.lineCap = 'round'; // 线条端点圆角
// 2. 开始绘制(鼠标按下/触摸开始)
function startDrawing(e) {
isDrawing = true; // 标记为正在绘制
[lastX, lastY] = getCoordinates(e); // 获取初始坐标(兼容鼠标/触摸)
placeholder.style.display = 'none'; // 隐藏占位提示
signatureData.push([]); // 新增一段绘制数据(存储当前笔画)
}
// 3. 绘制中(鼠标移动/触摸滑动)
function draw(e) {
if (!isDrawing) return; // 未标记绘制时跳过
e.preventDefault(); // 阻止触摸设备上的默认滚动
const [x, y] = getCoordinates(e); // 获取当前坐标
// 绘制线条:从上次坐标到当前坐标
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
// 保存当前坐标到绘制数据(用于后续重新渲染)
signatureData[signatureData.length - 1].push({ x, y });
[lastX, lastY] = [x, y]; // 更新上次坐标
}
// 4. 结束绘制(鼠标抬起/触摸结束)
function stopDrawing() {
isDrawing = false; // 取消绘制标记
}
// 5. 坐标转换(兼容鼠标与触摸事件)
function getCoordinates(e) {
let x, y;
if (e.type.includes('touch')) { // 触摸事件:获取触摸点相对于Canvas的坐标
x = e.touches[0].clientX - canvas.getBoundingClientRect().left;
y = e.touches[0].clientY - canvas.getBoundingClientRect().top;
} else { // 鼠标事件:直接获取相对于Canvas的偏移坐标
x = e.offsetX;
y = e.offsetY;
}
return [x, y];
}
// 6. 绑定绘制事件(鼠标+触摸)
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing); // 鼠标离开画布时结束绘制
canvas.addEventListener('touchstart', startDrawing);
canvas.addEventListener('touchmove', draw);
canvas.addEventListener('touchend', stopDrawing);
// 防止触摸绘制时页面滚动(passive: false 允许 preventDefault)
canvas.addEventListener('touchmove', function (e) {
if (isDrawing) e.preventDefault();
}, { passive: false });
- 样式控制逻辑(颜色 + 粗细)
实现签名样式的实时调整,视觉反馈即时:
javascript
// 颜色选择:点击颜色块切换签名颜色
colorOptions.forEach(option => {
option.addEventListener('click', function () {
// 移除所有选项的active类,避免多选中
colorOptions.forEach(opt => opt.classList.remove('active'));
// 为当前选中选项添加active类,视觉标识
this.classList.add('active');
// 更新当前颜色,并同步到Canvas绘制样式
currentColor = this.getAttribute('data-color');
ctx.strokeStyle = currentColor;
});
});
// 线条粗细:拖动滑块调整,实时显示数值
lineWidthInput.addEventListener('input', function () {
currentLineWidth = this.value;
ctx.lineWidth = currentLineWidth; // 同步到Canvas绘制样式
widthValue.textContent = `${currentLineWidth}px`; // 更新数值显示
});
各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!