Отримайте позицію (X, Y) елемента HTML щодо вікна браузера


1566

Я хочу знати, як отримати X і Y позицію елементів HTML, таких як imgі divв JavaScript, відносно вікна браузера.


134
Відносно чого?
AnthonyWJones

4
я використовував ці 7 рядків коду, який працює у всіх браузерах з розбіжностями в ie5,6,7 (я не пам’ятаю, щоб мати будь-яку проблему ... може бути тип документа) ... quirksmode.org/js/findpos. html, і я багато використовував його стільки років. може хтось може вказати на недоліки, якщо такі є.
Джаяпал Чандран

98
@AnthonyWJones, я припускаю, що вам потрібне було педантичне задоволення, але очевидно, як це завжди, коли не визначено, що ОП посилається на найзагальніший випадок або стосується віконних координат браузера.
Мотес

7
@Mote, Ні, це не так очевидно. Залиште вбік, суб’єктивність та помилкові аксіоми. Це може бути відносно вікна перегляду або вгорі сторінки (він же document.documentElement).
Andre Figueiredo

15
Дефолт у найбільш загальному не є висновком, це логічна прогресія, так що це буде відносно вікна, або "вершина сторінки" може бути терміном, як ви його сказали. У Теорії ігор кодифіковано як поняття, яке називається точкою Шеллінга. Обов’язково вкажіть, коли ви не маєте на увазі найзагальніший випадок.
Мотес

Відповіді:


1795

Правильний підхід полягає у використанні element.getBoundingClientRect():

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer підтримує це з тих пір, поки ви, швидше за все, не піклуєтесь про це, і це було остаточно стандартизовано в CSSOM Views . Усі інші браузери його прийняли давно .

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

Повернені значення element.getBoundingClientRect()відносно вікна перегляду. Якщо вам це потрібно відносно іншого елемента, просто відніміть один прямокутник від іншого:

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');

143
Дуже цікава стаття на JS координати . Ця стаття ніде не згадується про SO, вона повинна ..
e2-e4

6
Не працює ... це 8 пікселів вертикально та горизонтально, через 8px поля в корпусі. Рішення Меуу працює чудово. Якщо ви хочете, у мене невеликий тест, щоб продемонструвати проблему.
CpnCrunch

3
Насправді, я думаю, це залежить від того, що ви насправді хочете отримати координати. Питання трохи неоднозначне. Ваша відповідь правильна, якщо ви просто хочете, щоб координати відносно вікна перегляду або відносно елемента тіла, але це не допоможе вам у тому випадку, коли ви хочете абсолютного положення елемента (який я думаю, те, чого хочуть більшість людей) . відповідь meouw теж не дає цього, якщо ви не видалите біти '-scrollLeft' і '-scrollTop'.
CpnCrunch

4
@CpnCrunch: я бачу, що ти маєш на увазі зараз; Я не розумів, що ви маєте на увазі останню частину моєї відповіді. Коли корпус має поле, його обмежувальне поле буде зміщене на таку кількість пікселів на кожній відповідній стороні. У цьому випадку вам також доведеться віднімати обчислений стиль поля з координат тіла. Варто відзначити, що CSS скидає вилучення поля <body>.
Енді Е

3
element.getBoundingClientRect().topне повертає правильного верхнього зміщення у випадку position: fixedелемента в iOS (iPhone 8), якщо він містить сфокусований вхідний елемент і віртуальна клавіатура зісковзнула вгору. Наприклад, якщо фактичне зміщення у верхній частині вікна дорівнює 200 пікселів, воно повідомляє про це як 420 пікселів, де 220 пікселів - висота віртуальної клавіатури. Якщо встановити елементи елемента position: absoluteі розташувати його в тому ж самому положенні, що і зафіксовано, ви отримаєте правильний 200px. Я не знаю рішення для цього.
Яніс Елмеріс

327

Бібліотеки мають деяку довжину, щоб отримати точні зрушення для елемента.
ось проста функція, яка виконує роботу за будь-яких обставин, які я намагався.

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 

14
зміна: el = el.parentNode на: el = el.offsetParent; і, здається, зараз працює для вкладених кадрів ... Я думаю, це те, що ти задумав?
Адам

4
Це рішення є неповним. Спробуйте покласти товсту облямівку на диву і вкладіть її кілька разів. У будь-якій версії Firefox (2-5) вона буде вимкнена за шириною меж (навіть у режимі дотримання стандартів).
ck_

3
Чи не існує чистішого способу зробити це, як функція el.totalOffsetLeft та totalOffsetTop? jQuery, безумовно, має такий варіант, але шкода, що для цього немає офіційного методу, нам потрібно чекати DOM4? Я будую програму для полотна HTML5, тому я думаю, що найкращим рішенням було б вставити елемент полотна в iframe, щоб я міг отримати реальні координати з clientX та clientY, коли натискаємо на елемент.
baptx

1
Отже, @Adam і meouw, ти кажеш, перший блок коду невірний? Тоді чому б не зняти це взагалі? (Це питання бачили досить багато глядачів протягом багатьох років; можливо, буде приємно видалити речі, якщо вони неправильні?)
Ар'ян

2
@baptx: Я знаю, що це пізня відповідь, але я не побачив ваш коментар раніше. Дивіться мою відповідь нижче щодо альтернативи, яка відповідає стандартам - вам навіть навіть не потрібен резервний код, оскільки браузери його підтримують давно.
Енді Е

242

Це працювало для мене (змінено з найвищої відповіді):

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

За допомогою цього ми можемо зателефонувати

getOffset(element).left

або

getOffset(element).top

1
Тільки це рішення працює для мене, коли розміщується елемент, в divцентрі якого використовується css top:50%, left:50%; transform:translate(-50%, -50%);... відмінно. Погодьтеся з питанням про @ScottBiggs. Логічно - шукати простоти.
нелек

3
можливо, це не переможець, тому що це те саме, що рішення Енді Е, але він не працює у старих браузерах <IE9
niltoid

getBoundingClientRect спричиняє масштабний сплеск перефарбовування в моїх графіках роботи
frumbert

1
Ви повинні визначити , rectвикористовуючи var, letабо const. В іншому випадку він визначається як window.rect.
hev1

2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)поверне середнє положення елемента
abhishake

96

Якщо ви хочете, щоб це було зроблено лише у javascript , ось декілька лайнерів, що використовуютьgetBoundingClientRect()

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

Перший рядок поверне offsetTopслово Y щодо документа. Другий рядок поверне offsetLeftслово X щодо документа.

getBoundingClientRect() - функція javascript, яка повертає положення елемента відносно вікна перегляду вікна.


2
Це має бути рішенням. Тут немає довгих кодів коду, його зрозуміле і дуже точне!
E Alexis MT

2
що робити, якщо елемент знаходиться в межах прокручуваного елемента? Єдиний спосіб зробити це - підсумовувати offsetTop усіх батьківських елементів, як це підказує інші відповіді
Дмитро Писарев

Як констатує Дмитро, це неправильно і дуже хибно. У неї не повинно бути стільки голосів, скільки в них. ВЖЕ ВИНАГИ буде і в прокручуваному елементі, оскільки сам документ можна прокручувати. Іншими словами, якщо весь документ не вміщується у вікні перегляду, він завжди буде неправильним, якщо користувач взагалі прокручує головне вікно.
Лев

46

Елементи HTML у більшості браузерів матимуть:

offsetLeft
offsetTop

Вони вказують положення елемента щодо його найближчого батька, який має макет. Цей батько часто може отримати доступ до властивості offsetParent.

IE і FF3 є

clientLeft
clientTop

Ці властивості зустрічаються рідше, вони задають позицію елементів із клієнтською областю батьків (вкладена область є частиною клієнтської області, але межа та межа не є).


36

Якщо сторінка включає - принаймні, будь-який "DIV", функція, надана meouw, викидає значення "Y" за межі поточних сторінок. Для того, щоб знайти точну позицію, вам потрібно обробити як зміщення, так і батьківські та батьківські.

Спробуйте вказаний нижче код (він перевіряється на FF2):


var getAbsPosition = function(el){
    var el2 = el;
    var curtop = 0;
    var curleft = 0;
    if (document.getElementById || document.all) {
        do  {
            curleft += el.offsetLeft-el.scrollLeft;
            curtop += el.offsetTop-el.scrollTop;
            el = el.offsetParent;
            el2 = el2.parentNode;
            while (el2 != el) {
                curleft -= el2.scrollLeft;
                curtop -= el2.scrollTop;
                el2 = el2.parentNode;
            }
        } while (el.offsetParent);

    } else if (document.layers) {
        curtop += el.y;
        curleft += el.x;
    }
    return [curtop, curleft];
};

1
як і в інших рішеннях, навіть при FF 24.4, вищевказаний код не працює, коли ширини меж є частиною макета позиціонування.
пограбувати

Ти рятівник життя. Я зараз працюю над деякими досить глибокими помилками GWT, і кидання цього методу JSNI вирішує всі мої проблеми !!
Буде Бірн

35

Ви можете додати два властивості, щоб Element.prototypeотримати верхній / лівий верх будь-якого елемента.

Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
    get: function () { 
        return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
    }
} );

Це називається так:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

Ось демонстрація порівняння результатів з jQuery offset().topта .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/


14
модифікація, Element.prototypeяк правило, вважається поганою ідеєю . Це призводить до дійсно важкого у підтримці коду. Також цей код не враховує прокрутку.
Джаред Форсайт

23

Для ефективного пошуку позиції щодо сторінки та без використання рекурсивної функції: (включає також IE)

var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
                document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?                   
                 document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;

Включення всіх важливих scrollTop / scrollLeft робить цю відповідь трохи правильнішою.
сканліфф

19

Як щодо чогось подібного, передаючи ідентифікатор елемента, і він поверне лівий або верхній, ми також можемо їх поєднати:

1) знайти ліворуч

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2) знайти верх

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

або 3) знайти ліворуч і зверху разом

function findTopLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');

16

Вам може бути краще, використовуючи рамку JavaScript, яка має функції повернення такої інформації (та багато іншого!) Незалежно від браузера. Ось декілька:

З цими рамками ви можете зробити щось на кшталт: $('id-of-img').top отримати y-піксельну координату зображення.


2
@Costa Всі вони використовують такі функції, хоча це поле, що розвивається, оскільки різні браузери по-різному відповідають специфікації. Так багато коду стосується "виправлення" речей, які йдуть не так. Вам справді слід подивитися вихідний код.
Шалом Креймер

18
@scraimer: jQuery та YUI НЕ є рамками !!! Це бібліотеки ! Це не те саме. Посилаючись на jquery.com : "jQuery - це швидка, маленька та багатофункціональна бібліотека JavaScript ." Посилаючись на yuilibrary.com (ви можете побачити "магічне" слово і в URL-адресі ...): "YUI - це безкоштовна бібліотека JavaScript та CSS з відкритим кодом для створення інтерактивних веб-додатків."
Sk8erPeter

29
Тож вам слід використовувати величезні бібліотеки саме для цього простого завдання? Не Необхідно. Я ненавиджу, що кожного разу, коли мені хочеться щось робити з js, я отримую ці рішення jQuery. jQuery - це не JS!
Opptatt Jobber

1
@OpptattJobber Я згоден ... JQuery - це не JavaScript. Він покладається на Javascript, але зовсім інша мова програмування.
Нік Меннінг

5
@NickManning Це не нова мова, це шар абстракції для DOM, що виключає необхідність запису сумісності та обхідних можливостей безпосередньо у ваш код. Якщо ви не використовуєте jQuery, у будь-якому випадку вам слід використовувати якийсь шар абстракції.
ginman

15

jQuery .offset () отримає поточні координати першого елемента або встановить координати кожного елемента у наборі відповідних елементів відносно документа.


Чомусь це не дає однакових результатів в IE порівняно з іншими браузерами. Я думаю, що в IE це дає позицію відносно вікна, тому якщо ви прокрутите, ви отримаєте інші результати в IE порівняно з іншими
Абдул Рахім Хаддад

1
offset () плутається із збільшенням, принаймні, в Android Chrome, тому марно. stackoverflow.com/a/11396681/1691517 показує спосіб, орієнтований на збільшення.
Тімо Кахьонен

10

Я взяв відповідь @ meouw, додав у clientLeft, що дозволяє межу, а потім створив три версії:

getAbsoluteOffsetFromBody - подібно до @ meouw's, це отримує абсолютне положення відносно елемента тіла або html документа (залежно від режиму примх)

getAbsoluteOffsetFromGivenElement - повертає абсолютне положення відносно даного елемента (RelaEl). Зауважте, що даний елемент повинен містити елемент el, інакше це буде поводитись так само, як getAbsoluteOffsetFromBody. Це корисно, якщо у вас є два елементи, що містяться в іншому (відомому) елементі (необов'язково кілька вузлів вгору по дереву вузла) і хочете зробити їх однаковими.

getAbsoluteOffsetFromRelative - повертає абсолютне положення відносно першого батьківського елемента з позицією: відносно. Це схоже на getAbsoluteOffsetFromGivenElement, з тієї ж причини, але буде йти лише до першого елемента, що відповідає.

getAbsoluteOffsetFromBody = function( el )
{   // finds the offset of el from the body or html element
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{   // finds the offset of el from relativeEl
    var _x = 0;
    var _y = 0;
    while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromRelative = function( el )
{   // finds the offset of el from the first parent with position: relative
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
        if (el != null)
        {
            if (getComputedStyle !== 'undefined')
                valString = getComputedStyle(el, null).getPropertyValue('position');
            else
                valString = el.currentStyle['position'];
            if (valString === "relative")
                el = null;
        }
    }
    return { top: _y, left: _x };
}

Якщо у вас все ще виникають проблеми, зокрема пов’язані з прокруткою, ви можете спробувати подивитися на http://www.greywyvern.com/?post=331 - я помітив принаймні один фрагмент сумнівного коду в getStyle, який повинен бути нормальним, якщо браузери поводяться , але решту взагалі не перевірили.


Цікаво ... але на Edge getAbsoluteOffsetFromBody (елемент) .top повертає інше значення під час прокрутки, в Chrome він залишається послідовним, коли я прокручую. Здається, Edge регулюється положенням прокрутки. Коли елемент прокручується з поля зору, я отримую негативне значення.
Норман

getAbsoluteOffsetFromRelative зробив свій день, мені довелося відтворювати підказку для завантаження без Javascript bootstrap, це мені дуже допомогло.
Нолюрн

На всякий випадок, якщо Меуу змінить своє ім’я користувача, посилання на відповідь: stackoverflow.com/a/442474/3654837 . (Я не хочу набивати цю стару нитку, так так, я
додаю

8

якщо ви використовуєте jQuery, плагін розмірів відмінний і дозволяє точно вказати, що ви хочете.

напр

Відносна позиція, абсолютна позиція, абсолютна позиція без прокладки, з підкладкою ...

Продовжуємося, скажемо, що ви можете багато зробити з цим.

Плюс бонус від використання jQuery - це легкий розмір файлу та просте використання, після цього ви не повернетесь до JavaScript без нього.


8

Це найкращий код, який мені вдалося створити (працює і в iframes, на відміну від зміщення jQuery ()). Здається, веб-сайт має дещо іншу поведінку.

На основі коментаря meouw:

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        // chrome/safari
        if ($.browser.webkit) {
            el = el.parentNode;
        } else {
            // firefox/IE
            el = el.offsetParent;
        }
    }
    return { top: _y, left: _x };
}

Зверніть увагу, що вам потрібно jQueryбуде скористатися $.browser.webkit; Вам потрібно буде пограти, navigator.userAgentщоб зробити те ж саме з чистим JavaScript.
SP

2
$ .browser більше не доступний в останній версії jQuery
Gus

на жаль, навіть з FF 24.4 вищевказаний код не працює, коли ширини меж є частиною макета позиціонування.
пограбувати

8

Якщо ви використовуєте jQuery, це може бути простим рішенням:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>

8

Різниця між малим і маленьким

function getPosition( el ) {
    var x = 0;
    var y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
    x += el.offsetLeft - el.scrollLeft;
    y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
    }
    return { top: y, left: x };
}

Подивіться приклад координат: http://javascript.info/tutorial/coordinate


Це, на жаль, не працює для всіх елементів, які можна знайти всередині сучасного HTML-документа. Вбудовані <svg>елементи, наприклад, не мають offsetLeft, offsetTopі offsetParentвластивості.
Джонатан Юніс

Це справедливо DIVчи IMGні SVG. Переглянути "Подивіться приклади координат"? Ви можете знайти об'єкт svg - це виклик позиції getOffsetRect , спробуйте залежати від роботи об'єкта.
KingRider

7

Найчистіший підхід, який я знайшов, - це спрощена версія методики, що використовується jQuery's offset. Подібно до деяких інших відповідей, з яких вона починається getBoundingClientRect; Потім він використовує windowі, documentElementщоб налаштувати положення прокрутки, а також такі речі, як маржа на body(часто за замовчуванням).

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;


6

Незважаючи на те, що це дуже ймовірно, що буде втрачено внизу стільки відповідей, то найкращі рішення тут не працювали для мене.
Наскільки я міг сказати, жодна з інших відповідей не допомогла б.

Ситуація :
На сторінці HTML5 у мене було меню, яке було елементом nav всередині заголовка (не THE заголовка, а заголовка в іншому елементі).
Я хотів, щоб навігація трималася на вершині, коли користувач прокручував до неї, але раніше цього заголовок був абсолютним (тому я міг би його трохи накласти на щось інше).
Наведені вище рішення ніколи не викликали зміни, оскільки .offsetTop не збирався змінюватися, оскільки це був абсолютний позиціонований елемент. Крім того, властивість .scrollTop була просто вершиною самого верхнього елемента ... тобто 0 і завжди буде 0.
Будь-які тести, які я виконував, використовуючи ці два (і те ж саме з результатами getBoundingClientRect), не підказували б мені, якщо верхівка навігаційної панелі колись прокручується до верхньої сторінки сторінки, що переглядається (знову ж таки, як повідомляється в консолі, вони просто залишалися однаковими під час прокрутки сталося).

Рішення
Рішення для мене було використання

window.visualViewport.pageTop

Значення властивості pageTop відображає видимий розділ екрану, тому дозволяє мені відстежувати, де елемент посилається на межі області видимості.

Мабуть, не потрібно говорити, щоразу, коли я маю справу з прокруткою, я сподіваюся використовувати це рішення для програмного реагування на рух елементів прокрутки.
Сподіваюся, це допоможе комусь іншому.
ВАЖЛИВО ПРИМІТКА: Схоже, це працює в Chrome і Opera в даний час і, безумовно, не в Firefox (6-2018) ... поки Firefox підтримує visualViewport, я рекомендую НЕ використовувати цей метод (і, сподіваюся, вони незабаром ... це робить багато більше сенсу, ніж решта).


ОНОВЛЕННЯ:
Просто примітка щодо цього рішення.
Хоча я все ще вважаю те, що я виявив дуже цінним у ситуаціях, коли "... програмно реагують на рух елементів, що прокручуються". застосовується. Кращим рішенням проблеми, яку я мав, було використання CSS для встановлення позиції: липкийна стихію. Використовуючи липкий, ви можете залишити елемент у верхній частині, не використовуючи JavaScript (ПРИМІТКА. Можливо, це не буде настільки ефективно, як зміна елемента на фіксований, але для більшості використовує клейкий підхід, ймовірно, буде вище)

UPDATE01:
Тож я зрозумів, що для іншої сторінки у мене була вимога, коли мені потрібно було визначити положення елемента в м'яко складній програмі прокрутки (паралакса плюс елементи, які прокручуються повз як частина повідомлення). Я зрозумів у тому сценарії, що наступне надає значення, яке я використав, щоб визначити, коли щось робити:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

Сподіваюся, ця відповідь зараз є більш корисною.


це, ймовірно, буде на вершині такої кількості відповідей, коли ви клацаєте активну, щоб сортувати відповіді
lucchi

@lucchi: D добре, я думаю, я міг би видалити текст @ the top ... хоча я просто трапився на цьому ще раз і зрозумів, що знайшов краще рішення для власної проблеми ... хоча моя відповідь - це більше нога до більш повних відповідей. Я підозрюю, що мої вимоги були, можливо, не такими поширеними, що інші відповіді не спрацювали для мене?
MER

1
Я вдячний за вашу відповідь. Просто потрібно було сказати вам, що кожен, хто бажає, буде знати, що ви написали щось нове. Ви не самотні ....
lucchi

5

Я зробив це так, щоб він був сумісним із старими браузерами.

// For really old browser's or incompatible ones
    function getOffsetSum(elem) {
        var top = 0,
            left = 0,
            bottom = 0,
            right = 0

         var width = elem.offsetWidth;
         var height = elem.offsetHeight;

        while (elem) {
            top += elem.offsetTop;
            left += elem.offsetLeft;
            elem = elem.offsetParent;
        }

         right = left + width;
         bottom = top + height;

        return {
            top: top,
            left: left,
            bottom: bottom,
            right: right,
        }
    }

    function getOffsetRect(elem) {
        var box = elem.getBoundingClientRect();

        var body = document.body;
        var docElem = document.documentElement;

        var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
        var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;

        var clientTop = docElem.clientTop;
        var clientLeft = docElem.clientLeft;


        var top = box.top + scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
        var bottom = top + (box.bottom - box.top);
        var right = left + (box.right - box.left);

        return {
            top: Math.round(top),
            left: Math.round(left),
            bottom: Math.round(bottom),
            right: Math.round(right),
        }
    }

    function getOffset(elem) {
        if (elem) {
            if (elem.getBoundingClientRect) {
                return getOffsetRect(elem);
            } else { // old browser
                return getOffsetSum(elem);
            }
        } else
            return null;
    }

Детальніше про координати в JavaScript тут: http://javascript.info/tutorial/coordinate


4

Щоб отримати загальний зсув елемента, ви можете рекурсивно підсумовувати всі батьківські зміщення:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

за допомогою цієї функції утиліти загальний верхній зсув елемента dom:

el.offsetTop + getParentOffsets(el);

3
/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    var position = {
        top: el.offsetTop,
        left: el.offsetLeft
    };
    if (el.offsetParent) {
        var parentPosition = getDocumentOffsetPosition(el.offsetParent);
        position.top += parentPosition.top;
        position.left += parentPosition.left;
    }
    return position;
}

Дякую ThinkingStiff за відповідь , це лише інша його версія.


2

Я успішно використав рішення Енді Е, щоб розмістити модальний завантажувальний модуль 2 залежно від того, на яке посилання в рядку таблиці користувач натискає. Сторінка - це гобелен 5, а JavaScript нижче імпортується в клас сторінки Java.

javascript:

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

Мій модальний код:

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" 
 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
    <h3 id="myModalLabel">Modal header</h3>
</div>

<div class="modal-body">
    <t:zone t:id="modalZone" id="modalZone">
        <p>You selected service line number: ${serviceLineNumberSelected}</p>
    </t:zone>
</div>

<div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <!-- <button class="btn btn-primary">Save changes</button> -->
</div>

Посилання в циклі:

<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">       
    <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> 
        <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" 
            t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
            onmouseover="setLinkPosition(this);">
            <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
        </a>
    </td>

І java-код у класі сторінки:

void onServiceLineNumberSelected(String number){
    checkForNullSession();
    serviceLineNumberSelected = number;
    addOpenServiceLineDialogCommand();
    ajaxResponseRenderer.addRender(modalZone);
}

protected void addOpenServiceLineDialogCommand() {
    ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
        @Override
        public void run(JavaScriptSupport javascriptSupport) {
            javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
        }
    });
}

Сподіваюсь, це комусь допоможе, цей пост допомог.


Цей js-код мені допоміг. У мене є старий додаток для веб-форм, що використовує декілька заповнювачів заповнення. з кількома заповнювачами та неправильною розміткою. Використання body.getBoundingClientRect (), а потім використання його вершини в позиціонуванні було те, що мені було потрібно. Дякую.
Бред Мартін

1

Після довгих досліджень та тестувань, здається, це спрацює

function getPosition(e) {
    var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
    var x = 0, y = 0;
    while (e) {
        x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
        y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
        e = e.offsetParent;
    }
    return { x: x + window.scrollX, y: y + window.scrollY };
}

див. http://jsbin.com/xuvovalifo/edit?html,js,output


1

Я просто подумав, що я також викину це.
Мені не вдалося протестувати його в старих браузерах, але він працює в останній вершині 3. :)

Element.prototype.getOffsetTop = function() {
    return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
    return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
    return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};

0

Оскільки різні веб-переглядачі рендерують межі, прокладки, поля та інше по-різному. Я написав невелику функцію, щоб отримати верхні та ліві позиції конкретного елемента в кожному кореневому елементі, який потрібно в точному вимірі:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

Для отримання лівої позиції необхідно повернутися:

    return offsetRect.left - rootRect.left;

-1

Отримайте позицію діва щодо ліворуч та верху

  var elm = $('#div_id');  //get the div
  var posY_top = elm.offset().top;  //get the position from top
  var posX_left = elm.offset().left; //get the position from left 

Я проголосував за те, що праворуч знизу та справа - це не властивості офсету ()
MacroMan

@MacroMan, я поважаю ваше рішення, але в тексті я вже пояснив, що "знизу і справа код не перевіряється". Також я скоро оновлюю свій код.
Вішал

Я думаю , що це el.offsetTopі el.offsetLeft(ОП нічого про JQuery не сказати ... Я не знаю , чому ваш відповідь використовує JQuery або ...)
mesqueeb
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.