如何使用JavaScript截取div/canvas区域可见内容的屏幕截图
问题根因
你当前代码导出空白截图是三个核心错误导致的:
- 逻辑自引用错误:
takeScreenshot函数中你对刚创建的透明空canvas执行drawImage(canvas自身, 0,0),相当于把空白内容画到空白画布上,自然得不到有效内容。 - 原生API能力限制:Canvas 2D的
drawImage方法仅支持图片、其他canvas、视频这类已经光栅化的源,不能直接绘制普通DOM节点,没有办法靠原生浏览器API直接把div区域的页面内容画到canvas上。 - Canvas分辨率配置错误:你只给canvas设置了CSS样式宽高,没有设置标签原生的
width和height属性,canvas实际渲染分辨率是默认的300px*150px,和显示尺寸不匹配,就算有内容也会出现拉伸、模糊问题。 - 附带样式bug:原代码中
box-sizing属性拼写错误(多了空格)、截图按钮没有设置底部定位会遮挡画布区域,也会影响截图区域的准确性。
修复后可直接运行代码
以下代码可以直接粘贴到浏览器控制台执行,实现选框区域截图+表单弹出的完整逻辑:
// 动态加载DOM转Canvas依赖 function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = callback; document.head.appendChild(script); } Start(); function Start() { var button = document.createElement("button"); button.setAttribute("id", "mainBtn"); button.innerHTML = "+"; button.style.cursor = "pointer"; button.style.textTransform = "uppercase"; button.style.position = "absolute"; button.style.top = "50px"; button.style.left = "100px"; document.getElementsByTagName("body")[0].appendChild(button); button.addEventListener('click', CreateBox); } function CreateBox() { var button = document.getElementById("mainBtn"); button.style.display = "none"; var mainBox = document.createElement("div"); mainBox.setAttribute("id", "mainBox"); mainBox.style.position = "absolute"; mainBox.style.top = "50px"; mainBox.style.left = "130px"; mainBox.style.width = "400px"; mainBox.style.height = "400px"; mainBox.style.boxSizing = "border-box"; mainBox.style.zIndex = "99"; mainBox.style.display = "block"; mainBox.style.border = "10px solid rgb(222, 221, 221)"; var cover = document.createElement("div"); cover.setAttribute("id", "cover"); cover.style.position = "relative"; cover.style.width = "100%"; cover.style.height = "100%"; mainBox.appendChild(cover); var capture = document.createElement("canvas"); capture.setAttribute("id", "capture"); // 配置canvas实际渲染分辨率,和显示尺寸匹配 capture.width = 380; capture.height = 340; capture.style.width = "100%"; capture.style.height = "calc(400px - 50px)"; capture.style.display = "block"; capture.style.backgroundColor = "transparent"; cover.appendChild(capture); var captureBtn = document.createElement("button"); captureBtn.setAttribute("id", "capture-btn"); captureBtn.innerHTML = 'Click to enquiry'; captureBtn.style.backgroundColor = "rgb(222, 221, 221)"; captureBtn.style.border = "none"; captureBtn.style.width = "calc(100% + 20px)"; captureBtn.style.height = "50px"; captureBtn.style.fontWeight = "600"; captureBtn.style.fontSize = "25px"; captureBtn.style.position = "absolute"; captureBtn.style.left = "-10px"; captureBtn.style.bottom = "-10px"; captureBtn.style.cursor = "pointer"; captureBtn.addEventListener('click', takeScreenshot); cover.appendChild(captureBtn); document.getElementsByTagName("body")[0].appendChild(mainBox); } function takeScreenshot() { const box = document.getElementById('mainBox'); // 获取选框实际位置,计算需要截图的内部区域(排除边框和按钮) const boxRect = box.getBoundingClientRect(); const captureArea = { x: boxRect.left + 10, y: boxRect.top + 10, width: boxRect.width - 20, height: boxRect.height - 60 }; // 先隐藏选框本身,避免把选框、按钮截入结果 box.style.display = "none"; // 等待DOM重绘完成后执行截图 setTimeout(() => { html2canvas(document.body, { x: captureArea.x, y: captureArea.y, width: captureArea.width, height: captureArea.height, useCORS: true, scale: window.devicePixelRatio // 适配高DPI屏幕,保证截图清晰度 }).then(canvas => { const dataURL = canvas.toDataURL('image/png'); CreateForm(dataURL); }).catch(err => { console.error('截图失败:', err); CreateForm(''); }); }, 100); } function CreateForm(screenshotUrl) { var br = document.createElement("br"); var enquiryForm = document.createElement("div"); enquiryForm.setAttribute("id", "enquiry-form"); enquiryForm.style.position = "absolute"; enquiryForm.style.top = "30px"; enquiryForm.style.right = "500px"; enquiryForm.style.width = "400px"; enquiryForm.style.boxSizing = "border-box"; enquiryForm.style.zIndex = "99"; enquiryForm.style.border = "10px solid rgb(222, 221, 221)"; enquiryForm.style.display = "block"; var formImage = document.createElement("div"); formImage.setAttribute("class", "form-image"); formImage.style.width = "100%"; formImage.style.height = "350px"; var image = document.createElement("img"); image.setAttribute("class", "form-image"); image.src = screenshotUrl; image.style.width = "100%"; image.style.height = "350px"; image.style.objectFit = "cover"; formImage.appendChild(image); var form = document.createElement("form"); form.setAttribute("id", "form-details"); form.style.backgroundColor = "rgb(222, 221, 221)"; form.style.color = "black"; form.style.padding = "10px"; form.style.fontSize = "15px"; form.setAttribute("method", "post"); var FN = document.createElement("input"); FN.setAttribute("type", "text"); FN.setAttribute("name", "FullName"); FN.setAttribute("placeholder", "Full Name"); FN.style.width = "100%"; FN.style.height = "32px"; FN.style.borderRadius = "5px"; FN.style.border = "none"; FN.style.padding = "0 8px"; FN.style.boxSizing = "border-box"; var DOB = document.createElement("input"); DOB.setAttribute("type", "text"); DOB.setAttribute("name", "phone"); DOB.setAttribute("placeholder", "Phone no."); DOB.style.width = "100%"; DOB.style.height = "32px"; DOB.style.borderRadius = "5px"; DOB.style.border = "none"; DOB.style.padding = "0 8px"; DOB.style.boxSizing = "border-box"; var EID = document.createElement("input"); EID.setAttribute("type", "text"); EID.setAttribute("name", "emailID"); EID.setAttribute("placeholder", "E-Mail ID"); EID.style.width = "100%"; EID.style.height = "32px"; EID.style.borderRadius = "5px"; EID.style.border = "none"; EID.style.padding = "0 8px"; EID.style.boxSizing = "border-box"; var s = document.createElement("button"); s.innerHTML = "Submit"; s.style.width = "100%"; s.style.height = "32px"; s.style.cursor = "pointer"; s.style.borderRadius = "5px"; s.style.border = "none"; // 输入内容校验,所有字段填完才允许提交 const checkValid = () => { const canSubmit = FN.value.trim() && DOB.value.trim() && EID.value.trim(); s.style.pointerEvents = canSubmit ? 'auto' : 'none'; s.style.opacity = canSubmit ? '1' : '0.6'; }; FN.addEventListener('input', checkValid); DOB.addEventListener('input', checkValid); EID.addEventListener('input', checkValid); checkValid(); form.appendChild(FN); form.appendChild(br.cloneNode()); form.appendChild(DOB); form.appendChild(br.cloneNode()); form.appendChild(EID); form.appendChild(br.cloneNode()); form.appendChild(br.cloneNode()); form.appendChild(s); enquiryForm.appendChild(formImage); enquiryForm.appendChild(form); document.getElementsByTagName("body")[0].appendChild(enquiryForm); } // 加载截图依赖 loadScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js', () => { console.log('截图模块加载完成'); });
关键改动说明
- 替换了无效的自绘截图逻辑,通过DOM光栅化能力直接截取指定坐标区域的页面内容,截图前自动隐藏选框,不会把选框边框、操作按钮截入最终结果。
- 修复了所有样式bug:修正了
box-sizing拼写错误、调整了按钮定位、给canvas设置了匹配的渲染分辨率、补全了表单输入框的基础样式避免布局溢出。 - 增加了适配逻辑:自动适配高DPI屏幕保证截图清晰度,开启跨域图片支持,页面中允许跨域的图片可以正常被截入。
- 优化了交互体验:表单提交按钮默认禁用,所有输入框填写完成后才允许点击,截图生成后自动填充到表单的图片区域直接展示。
内容的提问来源于stack exchange,提问作者Noob_Coder
相关产品推荐
相关产品推荐

