Получить позицию / смещение элемента относительно родительского контейнера?


125

Я привык работать с jQuery. Однако в моем текущем проекте я использую zepto.js. Zepto не предоставляет такой position()метод, как jQuery. Zepto поставляется только с offset().

Любая идея, как я могу получить смещение контейнера относительно родителя с чистым js или с Zepto?


4
Проголосовал против принятия ответа jQuery (который даже не помечен как jQuery!) При задании вопроса JavaScript.
— Джон

@John вы заметили метку zepto?
— Supersharp

@Supersharp Используйте этот JavaScriptтег, когда используете чистый JavaScript. Если вы используете фреймворк или библиотеку, вы не используете JavaScriptтег. Если тебя зовут Джефф, я бы не стал называть тебя Салли.
— Джон

@John это мнение, но так устроено не так. Пожалуйста, прочтите руководство по тегам javascript. В этом случае его следует использовать вместе с тегом библиотеки.
— Supersharp

@Supersharp Да ТАК такой некомпетентный; буквальное раздувание тегов. 😒︎
— Джон

Ответы:


188

Предупреждение: jQuery, а не стандартный JavaScript

element.offsetLeftи element.offsetTopявляются чистыми свойствами javascript для поиска позиции элемента по отношению к нему offsetParent; ближайший родительский элемент с позицией relativeилиabsolute

В качестве альтернативы вы всегда можете использовать Zepto, чтобы получить позицию элемента И его родителя, и просто вычесть два:

var childPos = obj.offset();
var parentPos = obj.parent().offset();
var childOffset = {
    top: childPos.top - parentPos.top,
    left: childPos.left - parentPos.left
}

Это дает вам смещение дочернего элемента относительно его родителя, даже если родительский элемент не расположен.


9
Позиционированные staticэлементы не являются родителями смещения.
— Esailija

5
не используйте точки с запятой в фигурных скобках, используйте запятые
— Лука Боррионе

1
как насчет фиксированной позиции? они зачет родителей?
— Ayyash

1
Да, @ Ayya- position fixed также создает новый контекст смещения
— mmmeff

9
@vsync jQuery не является королем ничего с тех пор, как ie9 достиг EOL в январе 2016 года, у нас есть стандартизированный выбор DOM во всех основных браузерах, изучите чистый js. Также мнения о том, какой фреймворк использовать, не имеют места в SO, так как это сильно зависит от проекта и целевой платформы.
— Hans Koch

72

в чистом js просто используйте offsetLeftи offsetTopсвойства.
Пример скрипки: http://jsfiddle.net/WKZ8P/

var elm = document.querySelector('span');
console.log(elm.offsetLeft, elm.offsetTop);
p   { position:relative; left:10px; top:85px; border:1px solid blue; }
span{ position:relative; left:30px; top:35px; border:1px solid red; }
<p>
    <span>paragraph</span>
</p>


Спасибо. Есть ли также способ получить смещение для элемента parent.parent?
— matt

2
p.offsetTop + p.parentNode.offsetTopВы можете обернуть это рекурсивным вызовом функции, как это было предложено несколько лет назад PPK . Вы можете изменить функцию, чтобы передать количество уровней, на которые нужно подняться, или использовать селектор для имитации $(selector).parents(parentSelector). Я бы предпочел это решение, потому что реализация zepto работает только с поддерживающими браузерами, getBoundingClientsRectчего нет на некоторых мобильных устройствах.
— Torsten Walter

Я думал, что getBoundingClientsRectполучил широкую поддержку ... если кто-нибудь знает, какие мобильные телефоны не поддерживают его, мне было бы интересно (не могу найти ни одной таблицы поддержки для мобильных устройств).
— Нобита

Вероятно, это наиболее правильный ответ, даже если он не отмечен. Мое личное решение изменилось $(this).offset().leftна this.offsetLeft.
— adjwilli 06

Это также исправляет неправильное jQuery.position()поведение внутри 3D-преобразованного родителя, большое вам спасибо!
— rassoh 03

6

Я так сделал в Internet Explorer.

function getWindowRelativeOffset(parentWindow, elem) {
    var offset = {
        left : 0,
        top : 0
    };
    // relative to the target field's document
    offset.left = elem.getBoundingClientRect().left;
    offset.top = elem.getBoundingClientRect().top;
    // now we will calculate according to the current document, this current
    // document might be same as the document of target field or it may be
    // parent of the document of the target field
    var childWindow = elem.document.frames.window;
    while (childWindow != parentWindow) {
        offset.left = offset.left + childWindow.frameElement.getBoundingClientRect().left;
        offset.top = offset.top + childWindow.frameElement.getBoundingClientRect().top;
        childWindow = childWindow.parent;
    }

    return offset;
};

=================== вы можете назвать это так

getWindowRelativeOffset(top, inputElement);

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


1

Добавьте смещение события к смещению родительского элемента, чтобы получить абсолютную позицию смещения события.

Пример :

HTMLElement.addEventListener('mousedown',function(e){

    var offsetX = e.offsetX;
    var offsetY = e.offsetY;

    if( e.target != this ){ // 'this' is our HTMLElement

        offsetX = e.target.offsetLeft + e.offsetX;
        offsetY = e.target.offsetTop + e.offsetY;

    }
}

Когда целью события не является элемент, для которого событие было зарегистрировано, он добавляет смещение родительского элемента к текущему смещению события, чтобы вычислить «абсолютное» значение смещения.

Согласно веб-API Mozilla: «Свойство HTMLElement.offsetLeft, доступное только для чтения, возвращает количество пикселей, на которое верхний левый угол текущего элемента смещен влево внутри узла HTMLElement.offsetParent ».

В основном это происходит, когда вы регистрируете событие для родителя, который содержит еще несколько дочерних liэлементов , например: кнопку с внутренним значком или текстовым диапазоном, элемент с внутренними промежутками. и т.д...


А что насчет родителя родителя? А как насчет вложенных элементов, имеющих полосы прокрутки? А как насчет предыдущих элементов с отображением: нет? Истинное положение смещения документа практически невозможно вычислить, но механизм визуализации может это знать. Жаль, что простые свойства, такие как позиция документа, никогда не включались в DOM.
— Дэвид Спектор

@DavidSpector word

1

пример

Итак, если бы у нас был дочерний элемент с идентификатором «child-element», и мы хотели бы получить его левую / верхнюю позицию относительно родительского элемента, скажем, для div с классом «item-parent», мы бы используйте этот код.

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position.top);

Плагин Наконец, для самого плагина (с несколькими примечаниями, объясняющими, что происходит):

// offsetRelative (or, if you prefer, positionRelative)
(function($){
    $.fn.offsetRelative = function(top){
        var $this = $(this);
        var $parent = $this.offsetParent();
        var offset = $this.position();
        if(!top) return offset; // Didn't pass a 'top' element 
        else if($parent.get(0).tagName == "BODY") return offset; // Reached top of document
        else if($(top,$parent).length) return offset; // Parent element contains the 'top' element we want the offset to be relative to 
        else if($parent[0] == $(top)[0]) return offset; // Reached the 'top' element we want the offset to be relative to 
        else { // Get parent's relative offset
            var parent_offset = $parent.offsetRelative(top);
            offset.top += parent_offset.top;
            offset.left += parent_offset.left;
            return offset;
        }
    };
    $.fn.positionRelative = function(top){
        return $(this).offsetRelative(top);
    };
}(jQuery));

Примечание: вы можете использовать это при событии mouseClick или mouseover

$(this).offsetRelative("div.item-parent");

Я не вижу объяснения прокрутки. Может случиться много странных случаев.
— Дэвид Спектор

1

У меня есть другое решение. Вычесть значение родительского свойства из значения дочернего свойства

$('child-div').offset().top - $('parent-div').offset().top;

0

Конечно, это просто с чистым JS, просто сделайте это, работайте и для фиксированных и анимированных панелей HTML 5, я сделал и попробовал этот код, и он работает для любого браузера (включая IE 8):

<script type="text/javascript">
    function fGetCSSProperty(s, e) {
        try { return s.currentStyle ? s.currentStyle[e] : window.getComputedStyle(s)[e]; }
        catch (x) { return null; } 
    }
    function fGetOffSetParent(s) {
        var a = s.offsetParent || document.body;

        while (a && a.tagName && a != document.body && fGetCSSProperty(a, 'position') == 'static')
            a = a.offsetParent;
        return a;
    }
    function GetPosition(s) {
        var b = fGetOffSetParent(s);

        return { Left: (b.offsetLeft + s.offsetLeft), Top: (b.offsetTop + s.offsetTop) };
    }    
</script>

Вы тестировали все возможные случаи родительских узлов и свойств элементов? Учитывает ли это прокрутку и вложенную прокрутку?
— Дэвид Спектор
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.