Визначення позиції елементу за допомогою javascript

Опубліковано: 2009-01-12   01:09:20

HTML/CSSЯкщо подивитись на чудові демо з використанням фреймворків, таких як Mootools, наприклад MooFlow чи то Exc Documentation Center, то можна помітити безліч рухомих елементів. Для написання подібних скриптів необхідно мати набір функцій для визначення положення елемента на сторінці.

Зрозуміло, що такі складні скрипти краще писати на основі великих JavaScript framework'ів. Однак існує багато елементів інтерфейсу для створення яких не потрібно використовувати хоча б частину функцій великої бібліотеки. Що ж робити в такому випадку? Дописати всі необхідні функції самотужки

В чому власне проблема?

Всім хто певний час працював з javascript відомо, що будь-який елемент сторінки має купу властивостей, що відповідають за положення елементу на сторінці. Чому ж не скористатись ними?

style.left/style.top
Ні на що не впливають і не мають жодного значення, поки атрибут position елементу не встановлено в relative, absolute чи fixed, та не було встановлене це значення в стилі елементу. А таке буває доволі рідко.
offsetLeft/offsetTop
Повертають відповідні координати відносно батьківського елементу. Вже краще, однак це без додаткових маніпуляцій не дає змогу визначити положення елементу відносно лівого верхнього кута документу чи його видимої частини, що може бути досить корисним.

Офіцерська

Пошук функцій для визначення координат

За запитом в Google можна знайти безліч вже написаних функцій. І більшість з них написані лише для ідеального випадку. В моїй практиці, такого не зустрічалось..

Типовий варіант для отримання координати y виглядає так:

function getTop(e) {
var top = e.offsetTop;
while (e.offsetParent) {
e = e.offsetParent;
top += e.offsetTop;
}
return top;
}

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

На формі лежить прихований елемент, що повинен розгорнутись не розтягуючи форму після натиснення на інший елемент. Завдання доволі просте, якщо елемент менший за форму: e.style.display = 'none', при цьому позіціонування має бути absolute. А якщо більший, то такий елемент просто перекривався деякими елементами, що йшли за ним. Тому було вирішено виймати його з форми, та встановлювати в document.body причому в те ж самісіньке місце, де він і знаходився. Тут виявилось, що опиняється елемент значно нижче ніж був до цього.

Вдосконалені функції

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

Функція, що повертає абсолютні координати об'єкту:

function getAbsolutePosition(e) {
var left = 0;
var top = 0;
while (e.offsetParent) {
left += e.offsetLeft + (e.currentStyle ? (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
top += e.offsetTop + (e.currentStyle ? (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
e = e.offsetParent;
if (e.scrollLeft) left -= e.scrollLeft;
if (e.scrollTop) top -= e.scrollTop;
}
left += e.offsetLeft + (e.currentStyle ? (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
top += e.offsetTop + (e.currentStyle ? (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
return {x:left, y:top};
}

Ця функція повертає в результаті виконання об'єкт, що містить в собі координути x та y відносно лівого верхнього кута документу.

Що ж змінилось? Ця функція, на відміну від попередниці враховує два фактори, що можуть впливати на координати елемента: рамка об'єкту, та внутрішній зсув контейнера, що його містить. Для обробки границь об'єктів введено додаткову функцію:

Number.prototype.NaN0=function() {
return isNaN(this) ? 0 : this;
}

У випадку коли ширина границі не встановлена, повертається NaN. Виконувати арифметичні дії з ним не можна, тому додаємо для всіх чисел функцію перевірки на NaN, що повертає 0 у коли перевірка проходить успішно, та саме число в противному разі.

Залишилось написати функцію для отримання координат об'єкту відносно вікна браузера. Знову ж таки scrollTop та scrollLeft однак для document.documentElement, чи document.body:

function getAlignedPosition(e) {
var left = 0;
var top = 0;
while (e.offsetParent) {
left += e.offsetLeft + (e.currentStyle ? (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
top += e.offsetTop + (e.currentStyle ? (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
e = e.offsetParent;
if (e.scrollLeft) left -= e.scrollLeft;
if (e.scrollTop) top -= e.scrollTop;
}
var docBody = document.documentElement? document.documentElement: document.body;
left += e.offsetLeft + (e.currentStyle? (parseInt(e.currentStyle.borderLeftWidth)).NaN0(): 0) + (UserData.isIE ? (parseInt(docBody.scrollLeft)).NaN0() : 0) - (parseInt(docBody.clientLeft)).NaN0();
top += e.offsetTop + (e.currentStyle? (parseInt(e.currentStyle.borderTopWidth)).NaN0(): 0) + (UserData.isIE ? (parseInt(docBody.scrollTop)).NaN0() : 0) - (parseInt(docBody.clientTop)).NaN0();
return {x:left, y:top};
}

Все просто

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

Дякую всім за увагу!

Теги: javascript
Коментарі: 6
 

Коментарі:

virua2009-01-13 11:21:34 :

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

 
GrAndSE2009-01-14 21:45:52 :

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

 
virua2009-01-15 11:11:22 :

Давай на "ти", якщо не проти.

 
GrAndSE2009-01-15 22:38:21 :

Давай, якщо тобі так зручніше :) Буду намагатись не забути про це :)

 
nazar2009-12-24 03:51:41 :

якись кусок говнокода, я би в такому не копався навіть за руку і серце принцеси і пів королівства, не позорьте україну =))

 
GrAndSE2009-12-24 04:16:51 :

Ну-ну.. Аргументи в студію. пане герой.

 

Додати коментар

user

email

url

text

Повідомляти про новікоментарі