Отримати положення / зміщення елемента щодо батьківського контейнера?


125

Я звик працювати з jQuery. У моєму поточному проекті я використовую zepto.js. Zepto не надаєposition() метод, як jQuery. Zepto тільки приходить offset().

Будь-яка ідея, як я можу отримати зміщення контейнера відносно батьківського з чистим js або за допомогою Zepto?


4
Під час запитання питання щодо JavaScript, який приймає відповідь jQuery (яка навіть не позначена як jQuery!).
Джон

@John Ви помітили тег zepto?
Супершерп

@Supersharp Використовуйте JavaScriptтег, коли ви використовуєте чистий JavaScript. Якщо ви використовуєте рамку або бібліотеку, ви не використовуєте JavaScriptтег. Якщо тебе звати Джеффом, я б не називав тебе Саллі.
Іван

@John це думка, але це не так, як це працює. Прочитайте посібник з тегами javascript. У цьому випадку його слід використовувати разом з тегом бібліотеки.
Супершерп

@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не компенсується батьками.
Есаїлія

5
не використовуйте крапки з комою всередині дужок, використовуйте коми
Luca Borrione

1
як щодо виправленої позиції? вони компенсують батьків?
Айяш

1
Так, @ Ayya- позиція виправлена ​​також створює новий контекст зміщення
mmmeff

9
@vsync jQuery - не король нічого, оскільки ie9 досяг EOL в січні 2016 року, у нас є стандартизований вибір DOM у всіх основних браузерах, дізнаємося чисті js. Також думки про те, які рамки використовувати, не мають місця для ПЗ, оскільки це сильно залежить від проекту та цільової платформи.
Ганс Кох

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?
матовий

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

Я думав, що getBoundingClientsRectвін широко підтримується ... якщо хтось знає, які мобільні телефони його не підтримують, мені було б цікаво (не можу знайти жодної таблиці підтримки для мобільних телефонів).
Nobita

Це, мабуть, найправильніша відповідь, навіть якщо вона не позначена. Моє особисте рішення змінилося $(this).offset().leftна this.offsetLeft.
adjwilli

Це також виправляє неправильну jQuery.position()поведінку всередині 3d-трансформованого батька, дуже дякую!
rassoh

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

Приклад

Отже, якби у нас був дочірній елемент з ідентифікатором "дочірній елемент", і ми хотіли отримати його ліве / верхнє положення відносно батьківського елемента, скажімо, div, який мав клас "елемент-батьків", ми б використовувати цей код.

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 або події переходу миші

$(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.