使用JavaScript实现浏览器截图功能的全过程

在Web开发中实现网页截图功能可以帮助我们保存网页内容、生成海报、制作截图分享等,这篇文章主要介绍了用JavaScript实现浏览器截图功能的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下。

最近项目中要实现一个需求:

用户希望在上传文件时能够直接截图上传,并且要求能够截图浏览器外的内容。

多方查找之下找到了类似的解决方案,但个人感觉操作上有些抽象,仅供参考。

HTML部分

截图开始的按钮

<button id="start-screenshot" class="button">开始截图</button>

这里是canvas部分

<div id="screenshot-container">
       <canvas id="screenshot-canvas"></canvas>
       <div class="selection-area" id="selection-area" style="display: none;"></div>
       <div class="toolbar" id="screenshot-toolbar" style="display: none;">
           <button id="confirm-screenshot">确认</button>
           <button id="cancel-screenshot">取消</button>
       </div>
</div>

CSS部分

根据需求自行调整就好

#screenshot-container {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 9999;
}
 
#screenshot-canvas {
    position: absolute;
    top: 0;
    left: 0;
    cursor: crosshair;
}
 
.selection-area {
    position: absolute;
    border: 2px dashed #12B7F5;
    background-color: rgba(18, 183, 245, 0.1);
    pointer-events: none;
}
 
.toolbar {
    position: absolute;
    background-color: white;
    border-radius: 4px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
    padding: 5px;
    display: flex;
    gap: 5px;
}
 
.toolbar button {
    background-color: #12B7F5;
    color: white;
    border: none;
    padding: 5px 10px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
}
 
.toolbar button:hover {
    background-color: #0E9AD7;
}

JS部分(原生JS为例)

获取dom元素

const startButton = document.getElementById('start-screenshot'); // 开始截图按钮
const screenshotContainer = document.getElementById('screenshot-container'); // 获取的图片展示区
const canvas = document.getElementById('screenshot-canvas'); // canvas
const ctx = canvas.getContext('2d');
const selectionArea = document.getElementById('selection-area'); // 截图区域
const toolbar = document.getElementById('screenshot-toolbar'); // 截图时右下角的小弹框
const confirmButton = document.getElementById('confirm-screenshot'); // 确认按钮
const cancelButton = document.getElementById('cancel-screenshot'); // 取消按钮

变量定义

let isCapturing = false;
let isSelecting = false;
let startX = 0;
let startY = 0;
let endX = 0;
let endY = 0;
let screenCapture = null;

设置画布大小

function setCanvasSize() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}

开始截图方法

async function startScreenshot() {
   try {
       // 请求屏幕捕获
       screenCapture = await navigator.mediaDevices.getDisplayMedia({
           video: {
               cursor: 'always'
           }
       });
 
       // 获取视频轨道
       const videoTrack = screenCapture.getVideoTracks()[0];
        
       // 创建视频元素以捕获屏幕
       const videoElem = document.createElement('video');
       videoElem.srcObject = screenCapture;
        
       // 当视频加载完成后,绘制到画布上
       videoElem.onloadedmetadata = () => {
           videoElem.play();
            
           // 设置画布大小
           setCanvasSize();
            
           // 绘制视频帧到画布
           ctx.drawImage(videoElem, 0, 0, canvas.width, canvas.height);
            
           // 停止视频轨道
           videoTrack.stop();
            
           // 显示截图容器
           screenshotContainer.style.display = 'block';
           isCapturing = true;
       };
   } catch (err) {
       console.error('截图失败:', err);
       alert('截图失败,请确保您已授予屏幕捕获权限。');
   }
}

这里会请求屏幕捕获权限并获取屏幕内容,这里可以选择 浏览器标签页、windows打开的窗口、整个屏幕,确实可以获取到浏览器之外的内容。

更新选择区域

function updateSelectionArea() {
      const width = Math.abs(endX - startX);
      const height = Math.abs(endY - startY);
      const left = Math.min(startX, endX);
      const top = Math.min(startY, endY);
 
      selectionArea.style.display = 'block';
      selectionArea.style.left = left + 'px';
      selectionArea.style.top = top + 'px';
      selectionArea.style.width = width + 'px';
      selectionArea.style.height = height + 'px';
 
      // 更新工具栏位置
      toolbar.style.display = 'flex';
      toolbar.style.left = (left + width + 5) + 'px';
      toolbar.style.top = (top + height + 5) + 'px';
}

确认截图(在这里获取截图结果)

function confirmScreenshot() {
    if (!isCapturing) return;
 
    const width = Math.abs(endX - startX);
    const height = Math.abs(endY - startY);
    const left = Math.min(startX, endX);
    const top = Math.min(startY, endY);
 
    // 创建新画布以保存选定区域
    const resultCanvas = document.createElement('canvas');
    resultCanvas.width = width;
    resultCanvas.height = height;
    const resultCtx = resultCanvas.getContext('2d');
 
    // 将选定区域绘制到新画布
    resultCtx.drawImage(
        canvas,
        left, top, width, height,
        0, 0, width, height
    );
 
    // 在这里获取截图结果
    // 如果想生成成一个Base64url
    const base64Url = resultCanvas.toDataURL();
     
    // 如果想生成成一个File对象
    const resultFile = dataURLtoFile(resultCanvas.toDataURL(), "截图.png")
     
    // 重置截图状态
    resetScreenshot();
}

将Base64数据转换为File对象(不需要转换结果为文件对象可以不写这段)

function dataURLtoFile(dataurl, filename) {
    // 将Base64数据拆分为MIME类型和实际数据
    const arr = dataurl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1]; // 获取MIME类型
    const bstr = atob(arr[1]); // 解码Base64数据
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
 
    // 将解码后的数据转换为Uint8Array
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
 
    // 创建并返回File对象
    return new File([u8arr], filename, { type: mime });
}

取消截图

function cancelScreenshot() {
    resetScreenshot();
}

重置截图状态

function resetScreenshot() {
   isCapturing = false;
   isSelecting = false;
   selectionArea.style.display = 'none';
   toolbar.style.display = 'none';
   screenshotContainer.style.display = 'none';
   ctx.clearRect(0, 0, canvas.width, canvas.height);
}

各类监听事件

// 事件监听器
startButton.addEventListener('click', startScreenshot);
confirmButton.addEventListener('click', confirmScreenshot);
cancelButton.addEventListener('click', cancelScreenshot);
 
// 鼠标事件处理
canvas.addEventListener('mousedown', function(e) {
    if (!isCapturing) return;
 
    isSelecting = true;
    startX = e.clientX;
    startY = e.clientY;
    endX = e.clientX;
    endY = e.clientY;
    updateSelectionArea();
});
 
canvas.addEventListener('mousemove', function(e) {
    if (!isSelecting) return;
 
    endX = e.clientX;
    endY = e.clientY;
    updateSelectionArea();
});
 
canvas.addEventListener('mouseup', function() {
    isSelecting = false;
});
 
// 窗口大小改变时重新设置画布大小
window.addEventListener('resize', function() {
    if (isCapturing) {
        setCanvasSize();
    }
});

键盘快捷键(不需要可以不用)

// 键盘快捷键
document.addEventListener('keydown', function(e) {
    // Alt + A 开始截图
    if (e.altKey && e.key === 'a') {
        e.preventDefault();
        startScreenshot();
    }
     
    // Enter 确认截图
    if (e.key === 'Enter' && isCapturing) {
        confirmScreenshot();
    }
     
    // Esc 取消截图
    if (e.key === 'Escape' && isCapturing) {
        cancelScreenshot();
    }
});

完整代码

<!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>
        body {
            margin: 0;
            padding: 0;
            font-family: 'Microsoft YaHei', sans-serif;
            background-color: #f5f5f5;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            overflow: hidden;
        }
 
        .container {
            text-align: center;
            background-color: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            max-width: 800px;
            width: 100%;
        }
 
        .button {
            background-color: #12B7F5;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
            margin-top: 10px;
        }
 
        .button:hover {
            background-color: #0E9AD7;
        }
 
        #screenshot-container {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 9999;
        }
 
        #screenshot-canvas {
            position: absolute;
            top: 0;
            left: 0;
            cursor: crosshair;
        }
 
        .selection-area {
            position: absolute;
            border: 2px dashed #12B7F5;
            background-color: rgba(18, 183, 245, 0.1);
            pointer-events: none;
        }
 
        .toolbar {
            position: absolute;
            background-color: white;
            border-radius: 4px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            padding: 5px;
            display: flex;
            gap: 5px;
        }
 
        .toolbar button {
            background-color: #12B7F5;
            color: white;
            border: none;
            padding: 5px 10px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }
 
        .toolbar button:hover {
            background-color: #0E9AD7;
        }
    </style>
</head>
<body>
    <div class="container">
        <button "start-screenshot" class="button">开始截图</button>
    </div>
 
    <div "screenshot-container">
        <canvas "screenshot-canvas"></canvas>
        <div class="selection-area" "selection-area" style="display: none;"></div>
        <div class="toolbar" "screenshot-toolbar" style="display: none;">
            <button "confirm-screenshot">确认</button>
            <button "cancel-screenshot">取消</button>
        </div>
    </div>
 
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 元素引用
            const startButton = document.getElementById('start-screenshot');
            const screenshotContainer = document.getElementById('screenshot-container');
            const canvas = document.getElementById('screenshot-canvas');
            const ctx = canvas.getContext('2d');
            const selectionArea = document.getElementById('selection-area');
            const toolbar = document.getElementById('screenshot-toolbar');
            const confirmButton = document.getElementById('confirm-screenshot');
            const cancelButton = document.getElementById('cancel-screenshot');
 
            // 截图状态
            let isCapturing = false;
            let isSelecting = false;
            let startX = 0;
            let startY = 0;
            let endX = 0;
            let endY = 0;
            let screenCapture = null;
 
            // 设置画布大小
            function setCanvasSize() {
                canvas.width = window.innerWidth;
                canvas.height = window.innerHeight;
            }
 
            // 开始截图
            async function startScreenshot() {
                try {
                    // 请求屏幕捕获
                    screenCapture = await navigator.mediaDevices.getDisplayMedia({
                        video: {
                            cursor: 'always'
                        }
                    });
 
                    // 获取视频轨道
                    const videoTrack = screenCapture.getVideoTracks()[0];
                     
                    // 创建视频元素以捕获屏幕
                    const videoElem = document.createElement('video');
                    videoElem.srcObject = screenCapture;
                     
                    // 当视频加载完成后,绘制到画布上
                    videoElem.onloadedmetadata = () => {
                        videoElem.play();
                         
                        // 设置画布大小
                        setCanvasSize();
                         
                        // 绘制视频帧到画布
                        ctx.drawImage(videoElem, 0, 0, canvas.width, canvas.height);
                         
                        // 停止视频轨道
                        videoTrack.stop();
                         
                        // 显示截图容器
                        screenshotContainer.style.display = 'block';
                        isCapturing = true;
                    };
                } catch (err) {
                    console.error('截图失败:', err);
                    alert('截图失败,请确保您已授予屏幕捕获权限。');
                }
            }
 
            // 更新选择区域
            function updateSelectionArea() {
                const width = Math.abs(endX - startX);
                const height = Math.abs(endY - startY);
                const left = Math.min(startX, endX);
                const top = Math.min(startY, endY);
 
                selectionArea.style.display = 'block';
                selectionArea.style.left = left + 'px';
                selectionArea.style.top = top + 'px';
                selectionArea.style.width = width + 'px';
                selectionArea.style.height = height + 'px';
 
                // 更新工具栏位置
                toolbar.style.display = 'flex';
                toolbar.style.left = (left + width + 5) + 'px';
                toolbar.style.top = (top + height + 5) + 'px';
            }
 
            // 将Base64数据转换为File对象
            function dataURLtoFile(dataurl, filename) {
                // 将Base64数据拆分为MIME类型和实际数据
                const arr = dataurl.split(',');
                const mime = arr[0].match(/:(.*?);/)[1]; // 获取MIME类型
                const bstr = atob(arr[1]); // 解码Base64数据
                let n = bstr.length;
                const u8arr = new Uint8Array(n);
 
                // 将解码后的数据转换为Uint8Array
                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
 
                // 创建并返回File对象
                return new File([u8arr], filename, { type: mime });
            }
 
            // 确认截图
            function confirmScreenshot() {
                if (!isCapturing) return;
 
                const width = Math.abs(endX - startX);
                const height = Math.abs(endY - startY);
                const left = Math.min(startX, endX);
                const top = Math.min(startY, endY);
 
                // 创建新画布以保存选定区域
                const resultCanvas = document.createElement('canvas');
                resultCanvas.width = width;
                resultCanvas.height = height;
                const resultCtx = resultCanvas.getContext('2d');
 
                // 将选定区域绘制到新画布
                resultCtx.drawImage(
                    canvas,
                    left, top, width, height,
                    0, 0, width, height
                );
 
                // 在这里获取截图结果
                // 如果想生成成一个Base64url
                const base64Url = resultCanvas.toDataURL();
                 
                // 如果想生成成一个File对象
                const resultFile = dataURLtoFile(resultCanvas.toDataURL(), "截图.png")
 
                // 重置截图状态
                resetScreenshot();
            }
 
            // 取消截图
            function cancelScreenshot() {
                resetScreenshot();
            }
 
            // 重置截图状态
            function resetScreenshot() {
                isCapturing = false;
                isSelecting = false;
                selectionArea.style.display = 'none';
                toolbar.style.display = 'none';
                screenshotContainer.style.display = 'none';
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            }
 
            // 事件监听器
            startButton.addEventListener('click', startScreenshot);
            confirmButton.addEventListener('click', confirmScreenshot);
            cancelButton.addEventListener('click', cancelScreenshot);
 
            // 鼠标事件处理
            canvas.addEventListener('mousedown', function(e) {
                if (!isCapturing) return;
 
                isSelecting = true;
                startX = e.clientX;
                startY = e.clientY;
                endX = e.clientX;
                endY = e.clientY;
                updateSelectionArea();
            });
 
            canvas.addEventListener('mousemove', function(e) {
                if (!isSelecting) return;
 
                endX = e.clientX;
                endY = e.clientY;
                updateSelectionArea();
            });
 
            canvas.addEventListener('mouseup', function() {
                isSelecting = false;
            });
 
            // 键盘快捷键
            document.addEventListener('keydown', function(e) {
                // Alt + A 开始截图
                if (e.altKey && e.key === 'a') {
                    e.preventDefault();
                    startScreenshot();
                }
                 
                // Enter 确认截图
                if (e.key === 'Enter' && isCapturing) {
                    confirmScreenshot();
                }
                 
                // Esc 取消截图
                if (e.key === 'Escape' && isCapturing) {
                    cancelScreenshot();
                }
            });
 
            // 窗口大小改变时重新设置画布大小
            window.addEventListener('resize', function() {
                if (isCapturing) {
                    setCanvasSize();
                }
            });
        });
    </script>
</body>
</html>

总结

姑且算是实现了这个需求,但是实现效果并不是很理想,只能说仅供参考吧

到此这篇关于用JavaScript实现浏览器截图功能的文章就介绍到这了,更多相关JS浏览器截图功能内容请继续浏览下面的相关文章!