提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
需求简介
网页上某个元素截图,截图后需要显示
一、原理
浏览器提供的navigator.mediaDevices.getDisplayMedia方法可以实现录屏功能,我们将它投放到video标签中进行播放,然后截取其中的一帧。video标签放在最底层藏起来(display不能设none),计算目标元素的位置进行截图
二、实现
1.在页面中最底层放一个video标签,大小需要设置成屏幕的宽高。
2.计算浏览器位置,获取点击事件的鼠标在屏幕中的位置,在获取鼠标在浏览器中的位置,计算出浏览器在屏幕中的位置。这一步主要考虑浏览器未全屏。
3.计算元素在浏览器中的位置,递归获取元素与父元素的距离然后相加,注意需要处理浏览器的任务栏、菜单栏。
4.截图,将屏幕投入video中截取一帧后关闭投屏。
5.其他后续操作
测试代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div style="width: 100%; height: 100%; position: relative; top: 0; left: 0; z-index: 1; overflow-y: hidden;">
<video id="video" style="width: 1600; height: 900; position: absolute; top: 0; left: 0;" autoplay></video>
</div>
<div style="width: 100%; height: 100%; z-index: 2;">
<button onclick="screenshoutBtnClick()">截图</button>
<img id="showScreenShout" style="width: 320px; height: 200px;" />
<div id="needScreenShotArea" style="width: 320px; height: 200px; background-color: aqua;">
测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字
</div>
</div>
</body>
<script>
function init() {
if (window.screen) {
var video = document.getElementById('video');
video.style.width = window.screen.width + "px";
video.style.height = window.screen.height + "px";
}
}
init();
const displayMediaOptions = {
video: {
cursor: "always"
},
audio: false
};
let videoElem = document.getElementById("video");
function screenshoutBtnClick() {
var windowX = event.screenX - event.clientX;
var windowY = event.screenY - event.clientY;
navigator.mediaDevices.getDisplayMedia(displayMediaOptions).then(stream => {
videoElem.srcObject = stream;
setTimeout(() => {
var canvas = document.createElement("canvas");
canvas.width = videoElem.clientWidth;
canvas.height = videoElem.clientHeight;
var needScreenShotEl = document.getElementById('needScreenShotArea');
var pos = getPosition(needScreenShotEl);
var toolBarHeight = window.outerHeight - window.innerHeight;
canvas.getContext("2d").drawImage(videoElem, windowX + pos.left,
windowY + (document.fullscreenElement ? pos.top : pos.top),
needScreenShotEl.clientWidth, needScreenShotEl.clientHeight, 0, 0, canvas.width, canvas.height
);
var dataURL = canvas.toDataURL("image/png");
document.getElementById('showScreenShout').src = dataURL;
let tracks = videoElem.srcObject.getTracks();
tracks.forEach(track => track.stop());
videoElem.srcObject = null;
}, 200)
}).finally(() => {
});
}
function getPosition(node) {
//获取元素相对于其父元素的left值var left
var left = node.offsetLeft;
var top = node.offsetTop;
// 取得元素的offsetParent
current = node.offsetParent;
// 一直循环直到根元素
while (current != null) {
left += current.offsetLeft;
top += current.offsetTop;
current = current.offsetParent;
}
return {
"left": left,
"top": top
};
}
</script>
</html>
三、注意事项
1.浏览器安全策略
浏览器在https和localhost下才能无条件调用投屏,其它情况下需要设置白名单webrtc报错问题
2.元素位置计算
当前实现需要在屏幕100%显示下才能准确截取到目标元素,不是100%需要计算缩放