获取整个 DOM 包装边界客户端矩形
Getting entire DOM wrapping bounding client rect
我正在寻找一种方法来获得一个虚拟边界框,它将包裹在所有 DOM 元素中。
例如,2 个 100X100 px
尺寸的 div,其中一个 position absolute
放置在 top:0 left :0
,另一个放置在 top:700px left:700px
将导致 800X800
矩形(图片 1):
滚动时,我希望仍会得到一个 800X800
矩形,其中包含滚动距离的偏移量(图 2):
我正在考虑遍历 DOM,获取所有边界客户端矩形并手动计算,如下所示:
document.querySelectorAll("*").forEach((el)=>{
let r = el.getBoundingClientRect();
//calculate
})
不过,好像效率不是很高。任何帮助,将不胜感激。
更新:
这是到目前为止的代码,任何见解将不胜感激:
function getDocumentVisualBoundingBox() {
return Array.prototype.reduce.call(document.querySelectorAll("*"), (res, el) => {
//Looking at BODY element, Absolute positioned elements and ignoring elements within scrollable containers.
if (el.tagName === 'BODY' || (el.parentElement && getComputedStyle(el.parentElement).overflow === 'visible' && getComputedStyle(el).position === 'absolute')) {
let rect = el.getBoundingClientRect();
res.offsetLeft = Math.min(res.offsetLeft, rect.left);
res.offsetTop = Math.min(res.offsetTop, rect.top);
res.width = Math.max(res.width, rect.width + Math.abs(res.offsetLeft) + rect.left);
res.height = Math.max(res.height, rect.height + Math.abs(res.offsetTop) + rect.top);
}
return res;
}, {
offsetLeft: 0,
offsetTop: 0,
width: 0,
height: 0
});
}
如果您想使用绝对定位元素,那是不可能的,因为它们已从 DOM 流程中删除,如 here.
所述
您需要手动执行此操作,完全按照您说的去做。
我创建了一个小 fiddle 来玩这个(单击元素将子元素位置更改为相对位置以查看容器如何扩展):
var container = document.createElement("div");
container.classList.add("cont");
var a = document.createElement("div")
a.classList.add("abs");
var b = document.createElement("div")
b.classList.add("abs");
b.style.left = b.style.top = "100px";
container.appendChild(a);
container.appendChild(b);
document.body.appendChild(container);
document.body.addEventListener("click", () => {
a.style.position = b.style.position = a.style.position ? "" : "relative";
});
html, body {
margin: 0;
padding: 0;
}
.cont {
position: absolute;
display: inline;
background-color: blue;
}
.abs {
position: absolute;
width: 50px;
height: 50px;
background-color: red;
}
我最终编写了自己的方法:
function getDocumentVisualBoundingBox() {
return Array.prototype.reduce.call(document.querySelectorAll("*"), (res, el) => {
//Looking at BODY element, Absolute positioned elements and ignoring elements within scrollable containers.
if (el.tagName === 'BODY' || (el.parentElement && getComputedStyle(el.parentElement).overflow === 'visible' && getComputedStyle(el).position === 'absolute')) {
let rect = el.getBoundingClientRect();
res.offsetLeft = Math.min(res.offsetLeft, rect.left);
res.offsetTop = Math.min(res.offsetTop, rect.top);
res.width = Math.max(res.width, rect.width + Math.abs(res.offsetLeft) + rect.left);
res.height = Math.max(res.height, rect.height + Math.abs(res.offsetTop) + rect.top);
}
return res;
}, {
offsetLeft: 0,
offsetTop: 0,
width: 0,
height: 0
});
}
我正在寻找一种方法来获得一个虚拟边界框,它将包裹在所有 DOM 元素中。
例如,2 个 100X100 px
尺寸的 div,其中一个 position absolute
放置在 top:0 left :0
,另一个放置在 top:700px left:700px
将导致 800X800
矩形(图片 1):
滚动时,我希望仍会得到一个 800X800
矩形,其中包含滚动距离的偏移量(图 2):
我正在考虑遍历 DOM,获取所有边界客户端矩形并手动计算,如下所示:
document.querySelectorAll("*").forEach((el)=>{
let r = el.getBoundingClientRect();
//calculate
})
不过,好像效率不是很高。任何帮助,将不胜感激。
更新: 这是到目前为止的代码,任何见解将不胜感激:
function getDocumentVisualBoundingBox() {
return Array.prototype.reduce.call(document.querySelectorAll("*"), (res, el) => {
//Looking at BODY element, Absolute positioned elements and ignoring elements within scrollable containers.
if (el.tagName === 'BODY' || (el.parentElement && getComputedStyle(el.parentElement).overflow === 'visible' && getComputedStyle(el).position === 'absolute')) {
let rect = el.getBoundingClientRect();
res.offsetLeft = Math.min(res.offsetLeft, rect.left);
res.offsetTop = Math.min(res.offsetTop, rect.top);
res.width = Math.max(res.width, rect.width + Math.abs(res.offsetLeft) + rect.left);
res.height = Math.max(res.height, rect.height + Math.abs(res.offsetTop) + rect.top);
}
return res;
}, {
offsetLeft: 0,
offsetTop: 0,
width: 0,
height: 0
});
}
如果您想使用绝对定位元素,那是不可能的,因为它们已从 DOM 流程中删除,如 here.
所述您需要手动执行此操作,完全按照您说的去做。
我创建了一个小 fiddle 来玩这个(单击元素将子元素位置更改为相对位置以查看容器如何扩展):
var container = document.createElement("div");
container.classList.add("cont");
var a = document.createElement("div")
a.classList.add("abs");
var b = document.createElement("div")
b.classList.add("abs");
b.style.left = b.style.top = "100px";
container.appendChild(a);
container.appendChild(b);
document.body.appendChild(container);
document.body.addEventListener("click", () => {
a.style.position = b.style.position = a.style.position ? "" : "relative";
});
html, body {
margin: 0;
padding: 0;
}
.cont {
position: absolute;
display: inline;
background-color: blue;
}
.abs {
position: absolute;
width: 50px;
height: 50px;
background-color: red;
}
我最终编写了自己的方法:
function getDocumentVisualBoundingBox() {
return Array.prototype.reduce.call(document.querySelectorAll("*"), (res, el) => {
//Looking at BODY element, Absolute positioned elements and ignoring elements within scrollable containers.
if (el.tagName === 'BODY' || (el.parentElement && getComputedStyle(el.parentElement).overflow === 'visible' && getComputedStyle(el).position === 'absolute')) {
let rect = el.getBoundingClientRect();
res.offsetLeft = Math.min(res.offsetLeft, rect.left);
res.offsetTop = Math.min(res.offsetTop, rect.top);
res.width = Math.max(res.width, rect.width + Math.abs(res.offsetLeft) + rect.left);
res.height = Math.max(res.height, rect.height + Math.abs(res.offsetTop) + rect.top);
}
return res;
}, {
offsetLeft: 0,
offsetTop: 0,
width: 0,
height: 0
});
}