简体   繁体   中英

Efficiently Finding DOM Elements Appearing over a Specified DOM Element

How can I efficiently find all of the DOM elements that are on top of a specified query element?

That is, I want a Javascript function that when I pass in a reference to a DOM element will return an array of all DOM elements that have non-zero overlap with the input element and appear above it visually. My specific goal is to find those elements that may be visually blocking elements below them.

The context is one in which I do not have advanced knowledge of the web page, the query element, or much of anything else. Elements can appear above others for a variety of reasons.

I can of course do this through an exhaustive search of the DOM, but that's very inefficient and not practical when the DOM tree grows large. I could also use the newer elementFromPoint to sample positions from within the query element to ensure that it is indeed on top, but that seems pretty inefficient.

Any ideas on how to do this better?

Thanks!

I cannot think of a simpler way than using elementFromPoint. You don't seem to want to use it but can give you some consistent result. If there are multi layered elements, you should adapt your code to move already grabbed elements or set them invisible and recall function to get new set of data elements.

For the basic idea:

function upperElements(el) {
    var top = el.offsetTop,
        left = el.offsetLeft,
        width = el.offsetWidth,
        height = el.offsetHeight,
        elemTL = document.elementFromPoint(left, top),
        elemTR = document.elementFromPoint(left + width - 1, top),
        elemBL = document.elementFromPoint(left, top + height - 1),
        elemBR = document.elementFromPoint(left + width - 1, top + height - 1),
        elemCENTER = document.elementFromPoint(parseInt(left + (width / 2)), parseInt(top + (height / 2))),
        elemsUpper = [];
    if (elemTL != el) elemsUpper.push(elemTL);
    if (elemTR != el && $.inArray(elemTR, elemsUpper) === -1) elemsUpper.push(elemTR);
    if (elemBL != el && $.inArray(elemBL, elemsUpper) === -1) elemsUpper.push(elemBL);
    if (elemBR != el && $.inArray(elemBR, elemsUpper) === -1) elemsUpper.push(elemBR);
    if (elemCENTER != el && $.inArray(elemCENTER, elemsUpper) === -1) elemsUpper.push(elemCENTER);
    return elemsUpper;
}​

jsFiddle

It's unfortunate but there is no way to have a solution that will not iterate through all DOM element , because you can put any element anywhere on screen through CSS rules.

The best you can do it actually iterating over all the DOM elements to make a hit test.

If I had to do this, I would rely on jQuery, which is a widely used cross-browser API under constant improvement.

Take a look at http://api.jquery.com/position/ , http://api.jquery.com/width/ and http://api.jquery.com/height/

If performance is very important, you can gain a factor by diving into their implementation and improving it for your specific case, but keep in mind that the complexity will not go below O(number of DOM elements)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM