最终效果

一个全屏的画布,当你移动鼠标时,会留下彩色的轨迹,点击鼠标可以清除画布。

html5网页代码记录鼠标移动轨迹
(图片来源网络,侵删)

完整代码

你可以直接将以下代码复制到一个 .html 文件中,然后用浏览器打开即可。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">鼠标轨迹绘制器</title>
    <style>
        /* 基本样式,让画布占满整个窗口 */
        body {
            margin: 0;
            padding: 0;
            overflow: hidden; /* 防止出现滚动条 */
            background-color: #f0f0f0;
        }
        canvas {
            display: block; /* 移除 canvas 元素默认的内联空白 */
            cursor: crosshair; /* 将鼠标光标变为十字准星 */
        }
    </style>
</head>
<body>
    <canvas id="myCanvas"></canvas>
    <script>
        // 1. 获取 canvas 元素和其 2D 渲染上下文
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');
        // 2. 设置 canvas 的尺寸为窗口大小
        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }
        resizeCanvas();
        // 监听窗口大小变化,以便在调整窗口大小时重新设置 canvas 尺寸
        window.addEventListener('resize', resizeCanvas);
        // 3. 设置绘制样式
        ctx.lineWidth = 5; // 线条宽度
        ctx.lineCap = 'round'; // 线条末端为圆形
        ctx.lineJoin = 'round'; // 线条连接处为圆形
        // 4. 跟踪鼠标状态
        let isDrawing = false;
        let lastX = 0;
        let lastY = 0;
        // 5. 定义颜色数组,用于绘制彩色轨迹
        const colors = [
            '#FF6B6B', '#4ECDC4', '#45B7D1', '#FFBE0B', '#FB5607',
            '#8338EC', '#3A86FF', '#FF006E', '#C77DFF', '#7209B7'
        ];
        let currentColorIndex = 0;
        // 6. 绘制函数
        function draw(e) {
            // 如果鼠标没有按下,则不绘制
            if (!isDrawing) {
                return;
            }
            // 获取鼠标在 canvas 上的坐标
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            // 设置当前颜色
            ctx.strokeStyle = colors[currentColorIndex];
            // 开始绘制路径
            ctx.beginPath();
            // 移动到上一个点
            ctx.moveTo(lastX, lastY);
            // 画一条线到当前点
            ctx.lineTo(x, y);
            // 描边(绘制线条)
            ctx.stroke();
            // 更新上一个点的坐标为当前点
            lastX = x;
            lastY = y;
            // 更换颜色,实现彩虹效果
            currentColorIndex = (currentColorIndex + 1) % colors.length;
        }
        // 7. 事件监听器
        // 鼠标按下事件:开始绘制
        canvas.addEventListener('mousedown', (e) => {
            isDrawing = true;
            // 当鼠标按下时,记录当前鼠标位置作为路径的起点
            const rect = canvas.getBoundingClientRect();
            lastX = e.clientX - rect.left;
            lastY = e.clientY - rect.top;
        });
        // 鼠标移动事件:执行绘制
        canvas.addEventListener('mousemove', draw);
        // 鼠标松开或离开画布事件:停止绘制
        canvas.addEventListener('mouseup', () => {
            isDrawing = false;
        });
        canvas.addEventListener('mouseout', () => {
            isDrawing = false;
        });
        // 8. 清除画布功能(点击任意位置清除)
        canvas.addEventListener('click', () => {
            // 清除整个画布区域
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            // 重置颜色索引,从第一个颜色开始
            currentColorIndex = 0;
        });
    </script>
</body>
</html>

代码分步详解

HTML 结构 (<body>)

<body>
    <canvas id="myCanvas"></canvas>
</body>
  • 我们只需要一个核心元素:<canvas>,给它一个 id(这里是 myCanvas),方便 JavaScript 找到它。

CSS 样式 (<style>)

body {
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: #f0f0f0;
}
canvas {
    display: block;
    cursor: crosshair;
}
  • bodymarginpadding 设为 0overflow: hidden 是为了让页面没有边距,并且窗口大小改变时不会出现滚动条,让画布能完美填充整个视口。
  • canvasdisplay: block 可以移除 <canvas> 作为内联元素时自带的底部空白。
  • cursor: crosshair 将鼠标指针在画布上变为十字准星,提示用户可以在这里绘图。

JavaScript 逻辑 (<script>)

步骤 1 & 2:获取 Canvas 并设置尺寸

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
  • document.getElementById('myCanvas') 获取我们 HTML 中的 canvas 元素。
  • canvas.getContext('2d') 获取一个用于在画布上绘制 2D 图形的“上下文”(Context),所有的绘图操作(如画线、画圆、填充颜色)都是通过这个 ctx 对象来完成的。
  • resizeCanvas() 函数将 canvas 的宽度和高度设置为当前浏览器窗口的宽高,确保画布是全屏的。
  • 我们还添加了一个 resize 事件监听器,这样当用户调整浏览器窗口大小时,画布会自动适应新的尺寸。

步骤 3:设置绘制样式

ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
  • lineWidth 设置线条的粗细。
  • lineCap = 'round' 让线条的端点是圆形的,而不是方形。
  • lineJoin = 'round' 让两条线相交的连接处是圆滑的。

步骤 4:跟踪鼠标状态

let isDrawing = false;
let lastX = 0;
let lastY = 0;
  • isDrawing 是一个“开关”,用来判断用户当前是否正在按下鼠标并拖动。
  • lastXlastY 用来记录上一次鼠标的位置,因为画线需要起点和终点,所以我们必须知道从哪里画到哪里。

步骤 5:定义颜色数组

const colors = [...];
let currentColorIndex = 0;
  • 我们定义了一个漂亮的颜色数组,每次画线时,我们按顺序从这个数组中取颜色,形成彩虹轨迹的效果。

步骤 6:核心绘制函数 draw(e)

function draw(e) {
    if (!isDrawing) return;
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    ctx.strokeStyle = colors[currentColorIndex];
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(x, y);
    ctx.stroke();
    lastX = x;
    lastY = y;
    currentColorIndex = (currentColorIndex + 1) % colors.length;
}
  • 坐标计算e.clientXe.clientY 是鼠标相对于浏览器窗口左上角的坐标,如果页面有滚动或者 canvas 不是从 (0,0) 开始,我们需要用 canvas.getBoundingClientRect() 来获取 canvas 元素自身的偏移量,然后用 clientX - rect.leftclientY - rect.top 得到在 canvas 内部的准确坐标。
  • ctx.beginPath():开始一条新的、独立的路径,这非常重要,确保每次画线都是独立的,不会和之前的路径混在一起。
  • ctx.moveTo(lastX, lastY):将“画笔”移动到上一个记录的点。
  • ctx.lineTo(x, y):从当前画笔位置(即 moveTo 的点)画一条直线到新的鼠标位置 (x, y)
  • ctx.stroke():将上面定义的路径用 strokeStyle 设置的颜色和 lineWidth 设置的宽度“描边”出来,也就是画出我们看到的线条。
  • 更新状态:绘制完成后,将 lastXlastY 更新为当前点,为下一次绘制做准备,颜色索引 currentColorIndex 加 1,如果超出数组长度则取模,实现循环。

步骤 7:事件监听器

canvas.addEventListener('mousedown', (e) => { ... });
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', () => { ... });
canvas.addEventListener('mouseout', () => { ... });
  • mousedown:当鼠标在 canvas 上按下时,设置 isDrawing = true,并记录当前的鼠标位置作为 lastXlastY
  • mousemove:当鼠标在 canvas 上移动时,调用 draw() 函数,这是触发绘制的关键。
  • mouseup:当鼠标松开时,设置 isDrawing = false,停止绘制。
  • mouseout:当鼠标移出 canvas 区域时,也设置 isDrawing = false,防止鼠标移出后松开,但 isDrawing 状态没有重置。

步骤 8:清除画布功能

canvas.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    currentColorIndex = 0;
});
  • 我们监听 click 事件(即按下并松开)。
  • ctx.clearRect(x, y, width, height) 是一个非常有用的方法,它会清除指定矩形区域内的所有像素,我们用它来清除整个画布。
  • 重置 currentColorIndex,这样下次点击后,颜色会从数组的第一个开始。

如何扩展和改进?

  • 改变线条粗细:可以增加一个滑动条(<input type="range">)来动态改变 ctx.lineWidth
  • 选择颜色:可以添加一个颜色选择器(<input type="color">)来让用户自定义颜色。
  • 保存图片:可以添加一个按钮,点击后使用 canvas.toDataURL() 方法将画布内容保存为一张 PNG 图片。
  • 绘制模式:可以增加“绘制”和“擦除”模式,擦除模式其实就是将 globalCompositeOperation 设置为 'destination-out',这样画出的内容会变成透明。
html5网页代码记录鼠标移动轨迹
(图片来源网络,侵删)