基于 Vue 3 + html2canvas 实现网页任意区域截图组件

一、前言

在实际业务中,经常会有用户截图保存页面内容的需求,比如:

  • 表单填写后的结果截图
  • 页面中某个模块的操作记录截图
  • 可视化大屏、报表区域导出为图片

而我们可以通过 html2canvas 实现将 DOM 节点截图为图片。本篇文章将基于 Vue 3 + html2canvas 封装一个「可指定区域截图」的组件,支持:

  • ✅ 任意 DOM 区域截图
  • 🎯 鼠标框选截图区域
  • 🖼️ 图片预览与下载
  • 🧩 可插入业务模块作为截图内容

二、技术栈与原理简析

  • Vue 3 + <script setup>:组合式 API 更方便封装功能
  • html2canvas:将 HTML 节点渲染为 Canvas,再导出为图片
  • DOM 操作 + 鼠标事件监听:实现可视化选区

原理核心就是:将目标 DOM 渲染为 canvas,然后将 canvas 导出为 base64 或 Blob 图片。


三、项目准备

3.1 安装依赖

npm install html2canvas

3.2 页面基础布局

我们需要一个区域放置截图目标 + 控制按钮:

<template>
  <div class="screenshot-wrapper">
    <div class="toolbar">
      <button @click="captureFull">📷 截图整个区域</button>
      <button @click="toggleCropMode">✂️ 框选截图</button>
    </div>

    <!-- 可截图区域 -->
    <div class="capture-target" ref="captureRef">
      <slot />
    </div>

    <!-- 框选截图遮罩 -->
    <div v-if="cropMode" class="crop-mask" @mousedown="startCrop" />
  </div>
</template>

四、截图功能实现

4.1 整个区域截图

import html2canvas from 'html2canvas';

const captureRef = ref(null);

function captureFull() {
  html2canvas(captureRef.value).then(canvas => {
    const img = canvas.toDataURL('image/png');
    downloadImage(img);
  });
}

function downloadImage(dataUrl) {
  const a = document.createElement('a');
  a.href = dataUrl;
  a.download = 'screenshot.png';
  a.click();
}

五、框选截图功能

5.1 实现裁剪区域选择

const cropMode = ref(false);
const cropBox = reactive({ x: 0, y: 0, w: 0, h: 0 });
let startX = 0, startY = 0;

function toggleCropMode() {
  cropMode.value = !cropMode.value;
}

function startCrop(e) {
  const mask = e.currentTarget;
  startX = e.offsetX;
  startY = e.offsetY;

  const moveHandler = (moveEvent) => {
    cropBox.x = Math.min(startX, moveEvent.offsetX);
    cropBox.y = Math.min(startY, moveEvent.offsetY);
    cropBox.w = Math.abs(startX - moveEvent.offsetX);
    cropBox.h = Math.abs(startY - moveEvent.offsetY);
    drawCropBox(mask);
  };

  const upHandler = () => {
    document.removeEventListener('mousemove', moveHandler);
    document.removeEventListener('mouseup', upHandler);
    captureByCropBox();
    cropMode.value = false;
  };

  document.addEventListener('mousemove', moveHandler);
  document.addEventListener('mouseup', upHandler);
}

5.2 根据选区截图

function captureByCropBox() {
  html2canvas(captureRef.value).then(canvas => {
    const croppedCanvas = document.createElement('canvas');
    const ctx = croppedCanvas.getContext('2d');

    croppedCanvas.width = cropBox.w;
    croppedCanvas.height = cropBox.h;

    ctx.drawImage(
      canvas,
      cropBox.x, cropBox.y, cropBox.w, cropBox.h,
      0, 0, cropBox.w, cropBox.h
    );

    const croppedImg = croppedCanvas.toDataURL('image/png');
    downloadImage(croppedImg);
  });
}

5.3 选区样式绘制

function drawCropBox(maskEl) {
  let box = maskEl.querySelector('.crop-box');
  if (!box) {
    box = document.createElement('div');
    box.className = 'crop-box';
    maskEl.appendChild(box);
  }
  box.style.left = `${cropBox.x}px`;
  box.style.top = `${cropBox.y}px`;
  box.style.width = `${cropBox.w}px`;
  box.style.height = `${cropBox.h}px`;
}

六、样式美化

<style scoped>
.screenshot-wrapper {
  position: relative;
}
.toolbar {
  margin-bottom: 10px;
}
.capture-target {
  border: 1px solid #ccc;
  padding: 10px;
  background: #fff;
  position: relative;
}
.crop-mask {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
  cursor: crosshair;
  background-color: rgba(0,0,0,0.05);
}
.crop-box {
  position: absolute;
  border: 2px dashed #409EFF;
  background-color: rgba(64, 158, 255, 0.2);
  pointer-events: none;
}
</style>

七、使用示例

<template>
  <Screenshot>
    <div class="content">
      <h2>这是可截图区域</h2>
      <p>这里的内容将被截图,包括文字、图表等</p>
      <img src="https://via.placeholder.com/300x150" />
    </div>
  </Screenshot>
</template>

<script setup>
import Screenshot from './components/Screenshot.vue';
</script>

到这里,这篇文章就和大家说再见啦!我的主页里还藏着很多 篇 前端 实战干货,感兴趣的话可以点击头像看看,说不定能找到你需要的解决方案~
创作这篇内容花了很多的功夫。如果它帮你解决了问题,或者带来了启发,欢迎:
点个赞❤️ 让更多人看到优质内容
关注「前端极客探险家」🚀 每周解锁新技巧
收藏文章⭐️ 方便随时查阅
📢 特别提醒:
转载请注明原文链接,商业合作请私信联系
感谢你的阅读!我们下篇文章再见~ 💕

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值