2016-11-22 3 views
0

Я использую API document.elementFromPoint для получения элемента, находящегося в точке. Но я не хочу иметь все элементы - некоторые из них не квалифицированы, например, inline элементов. Поэтому я делаю неквалифицированные элементы временно невидимыми, чтобы захватить элемент, который находится под ним.Временно сделать элемент невидимым

Отмеченный код.

import { elementQualified, elementFromPoint } from './utils'; 

function makeInvisible(element) { 
    let oldVisibility = element.style.visibility; 

    /* this is supposed to make the element invisible immediately, without 
    * any delay. When a `transition` property is set which includes the 
    * `visibility` property, this is sometimes unfortunately not the case. */ 
    element.style.visibility = "hidden"; 

    /* this is the undo function being called at the end. */ 
    return() => { 
    element.style.visibility = oldVisibility; 
    }; 
} 

export default function(x, y) { 
    var undo = [], element, last; 

    /* in a loop, we grab the top-most element that is at a certain coordinate 
    * inside the viewport. The `last` variable is preventing an infinite loop 
    * in cases, where `makeInvisible()` does not work. */ 
    while (((element = elementFromPoint(x, y)) !== null) && (last !== element)) { 
    /* 
    * In order to be qualified, this element including its ancestors must 
    * all be qualified. For instance, if this is a block element but the 
    * parent for some reason is an inline element, this is not desired. */ 
    if (withAncestors(element).every(elementQualified)) { 
     break; 
    } 

    /* if the element is not qualified, we make it invisible and add it to the 
    * start of the `undo` array which is being batch-called after this loop. */ 
    undo.unshift(makeInvisible(element)); 

    /* and the loop protection */ 
    last = element; 
    } 

    /* undo all changes */ 
    undo.forEach((fn) => fn()); 

    /* check if we broke the loop or we have selected the topmost element 
    * in which case we discard the result. */ 
    if ((last === element) || (element === document.documentElement)) { 
    return null; 
    } 

    return element; 
} 

Если элемент, который должен стать невидимыми имеет набор transition свойства, которое включает в себя visibility свойства, оно не станет невидимым сразу. Возьмем, например, transition: all 0.3s ease-in-out. После установки element.style.visibility на hidden это займет 0.3s, после чего элемент фактически невидим и document.elementFromPoint выберет элемент под ним. В результате цикл прерывается, потому что document.elementFromPoint возвращает два раза идентичный элемент.

Я не собираюсь временно устанавливать свойство display, потому что он вызывает изменения компоновки, и я создаю инструмент, для которого изменения макета не работают.

+0

Cant удалить переход перед установкой элемента к невидимому и установить его обратно, как только вы сделано? – Lain

+0

«_ ... отображение свойства ... вызывает изменения макета». Это не так, когда вы выполняете всю обработку DOM синхронно и устанавливаете все, как было, прежде чем дать браузеру возможность отобразить страницу. Следовательно, установка 'display: none' в скрипте не будет отображаться на странице, если вы удалите стиль до окончания скрипта. – Teemu

+0

Я уже пробовал опцию 'display: none'. Это вызывает некоторые изменения макета и проблемы прокрутки для меня. – Vincent

ответ

1

Как Lain предположили, disable transitions на элементе в makeInvisible, то есть тайм-аут (1мс должен быть достаточно), сбрасывающим переход собственности

+1

Я выяснил, что это можно сделать без тайм-аута для повторного включения перехода. Я просто устанавливаю «видимость» в старое значение, а затем выставляю макет, прежде чем устанавливать свойство «переход». – Vincent