Recupera la posizione (X, Y) di un elemento HTML rispetto alla finestra del browser


1570

Voglio sapere come ottenere la posizione X e Y di elementi HTML come imge divin JavaScript rispetto alla finestra del browser.


134
Rispetto a cosa?
AnthonyWJones,

4
stavo usando queste 7 righe di codice che funzionano in tutti i browser con discrepanze in ie5,6,7 (non ricordavo di avere alcun proboem ... potrebbe essere il tipo di documento) ... quirksmode.org/js/findpos. html e l'ho usato molto per così tanti anni. può essere sciocco può indicare eventuali difetti.
Jayapal Chandran,

99
@AnthonyWJones, suppongo che tu abbia avuto bisogno del piacere pedante, ma è ovvio, come sempre quando non specificato, che l'OP si riferisce al caso più generale o alle coordinate della finestra del browser.
Motes,

7
@Mote, No, non è così ovvio. Lascia da parte inferenza, soggettività e falsi assiomi. Può essere relativo al viewport o all'inizio della pagina (aka document.documentElement).
Andre Figueiredo,

16
L'impostazione predefinita per il più generale non è inferenza, è la progressione logica, quindi sarebbe relativa alla finestra, o "inizio pagina" potrebbe essere il termine mentre lo metti. Nella teoria dei giochi, è codificato come un concetto chiamato punto di Schelling. Assicurati di specificare quando non intendi il caso più generale.
Motes,

Risposte:


1796

L'approccio corretto è usare element.getBoundingClientRect():

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

Internet Explorer lo supporta da quando è probabile che ti interessi e alla fine è stato standardizzato nelle viste CSSOM . Tutti gli altri browser lo hanno adottato molto tempo fa .

Alcuni browser restituiscono anche proprietà di altezza e larghezza, anche se questo non è standard. Se sei preoccupato per la vecchia compatibilità del browser, controlla le revisioni di questa risposta per un'implementazione degradante ottimizzata.

I valori restituiti da element.getBoundingClientRect()sono relativi alla finestra. Se ne hai bisogno rispetto ad un altro elemento, sottrai semplicemente un rettangolo dall'altro:

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

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

143
Un articolo molto interessante sulle coordinate JS . Questo articolo non è menzionato da nessuna parte su SO, dovrebbe ..
e2-e4,

6
Non funziona ... ha 8 pixel in verticale e in orizzontale, a causa del margine di 8px nel corpo. La soluzione di Meouw funziona perfettamente. Se vuoi ho un piccolo test per dimostrare il problema.
CpnCrunch,

3
In realtà, penso che dipenda da cosa vuoi ottenere davvero. La domanda è un po 'ambigua. La tua risposta è corretta se vuoi solo le coordinate relative al viewport o rispetto all'elemento body, ma ciò non ti aiuta nel caso in cui desideri la posizione assoluta dell'elemento (che immagino sia ciò che la maggior parte delle persone desidera) . La risposta di meouw non ti dà neanche questo, a meno che tu non rimuova i bit '-scrollLeft' e '-scrollTop'.
CpnCrunch,

4
@CpnCrunch: vedo cosa intendi ora; Non avevo capito che ti stavi riferendo all'ultima parte della mia risposta. Quando il corpo ha un margine, la sua casella di delimitazione sarà compensata da quel numero di pixel su ciascun lato rispettivo. In tal caso, dovresti anche sottrarre lo stile del margine calcolato dalle coordinate del corpo. Vale la pena notare che i ripristini CSS rimuovono il margine da <body>, però.
Andy E

3
element.getBoundingClientRect().topnon restituisce l'offset superiore corretto nel caso di un position: fixedelemento in iOS (iPhone 8) se contiene un elemento di input focalizzato e la tastiera virtuale è stata aperta. Ad esempio, se l'offset effettivo dalla parte superiore della finestra è 200 px, lo segnalerebbe come 420 px, dove 220 px è l'altezza della tastiera virtuale. Se imposti gli elementi position: absolutee li posizioni nella stessa posizione di quelli fissi, otterrai i 200px corretti. Non conosco una soluzione a questo.
Jānis Elmeris,

327

Le librerie fanno di tutto per ottenere offset accurati per un elemento.
ecco una semplice funzione che fa il lavoro in ogni circostanza che ho provato.

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
modifica: el = el.parentNode in: el = el.offsetParent; e sembra funzionare ora per iframe nidificati ... Sto pensando che è quello che intendevi?
Adam,

4
Questa soluzione è incompleta. Prova a mettere un bordo spesso su un div e annidalo alcune volte. In qualsiasi versione di Firefox (2-5) sarà disattivato dalla larghezza del bordo (s) (anche in modalità conformità standard).
ck_

3
non c'è un modo più pulito per farlo, come una funzione el.totalOffsetLeft e totalOffsetTop? jQuery ha certamente questa opzione ma è un peccato che non ci sia un metodo ufficiale per questo, dobbiamo aspettare DOM4? Sto creando un'applicazione canvas HTML5, quindi penso che la soluzione migliore sarebbe quella di inserire un elemento canvas in un iframe in modo da poter ottenere coordinate reali con clientX e clientY quando facciamo clic sull'elemento.
Baptx,

1
Quindi, @Adam e meouw, stai dicendo che il primo blocco di codice è sbagliato? Allora perché non rimuoverlo del tutto? (Questa domanda ha visto alcuni spettatori nel corso degli anni; potrebbe essere bello rimuovere le cose se sono sbagliate?)
Arjan

2
@baptx: so che questa è una risposta tardiva, ma non ho visto il tuo commento prima. Vedi la mia risposta di seguito per un'alternativa più conforme agli standard: non hai nemmeno davvero bisogno del codice di fallback, poiché i browser lo supportano da molto tempo.
Andy E

242

Questo ha funzionato per me (modificato dalla risposta più votata):

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

Usando questo possiamo chiamare

getOffset(element).left

o

getOffset(element).top

1
Solo questa soluzione funziona per me quando l'elemento viene inserito nel divcui centro usando css top:50%, left:50%; transform:translate(-50%, -50%);... eccellente. Accetto con la domanda di @ScottBiggs. Logico è cercare la semplicità.
Nelek,

3
forse non è un vincitore perché è uguale alla soluzione di Andy E, ma non funziona nei vecchi browser <IE9
niltoid,

getBoundingClientRect provoca un enorme picco di ridipingere nelle mie classifiche delle prestazioni
frumbert

1
È necessario definire rectusando var, leto const. Altrimenti, è definito come window.rect.
hev1

2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)restituirà la posizione centrale di un elemento
abhishake

97

Se vuoi farlo solo in javascript , ecco alcuni uno liners che utilizzanogetBoundingClientRect()

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

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

La prima riga restituirà la offsetTopdicitura Y relativa al documento. La seconda riga restituirà la offsetLeftdicitura X relativa al documento.

getBoundingClientRect() è una funzione javascript che restituisce la posizione dell'elemento rispetto alla finestra della finestra.


2
Questa dovrebbe essere la soluzione. Non c'è un lungo codice bs qui, è comprensibile ed è molto preciso!
E Alexis MT,

2
cosa succede se l'elemento si trova all'interno di un elemento scorrevole? L'unico modo per farlo è quello di sommare offsetTop di tutti gli elementi padre, come suggeriscono altre risposte
Dmitri Pisarev

Come afferma Dmitri, questo è errato e molto imperfetto. Non dovrebbe avere tanti voti positivi. Sarà SEMPRE in un elemento scorrevole anche perché il documento stesso può essere fatto scorrere. In altre parole, a meno che l'intero documento non si adatti alla finestra, sarà sempre errato se l'utente ha fatto scorrere la finestra principale.
Lev

46

Gli elementi HTML sulla maggior parte dei browser avranno: -

offsetLeft
offsetTop

Questi specificano la posizione dell'elemento rispetto al suo genitore più vicino che ha layout. È possibile accedere a questo genitore spesso tramite la proprietà offsetParent.

IE e FF3 hanno

clientLeft
clientTop

Queste proprietà sono meno comuni, specificano una posizione degli elementi con l'area client principale (l'area imbottita fa parte dell'area client ma il bordo e il margine no).


36

Se la pagina include - almeno - qualsiasi "DIV", la funzione fornita da meouw lancia il valore "Y" oltre i limiti di pagina correnti. Per trovare la posizione esatta, è necessario gestire sia offsetParent che parentNode.

Prova il codice indicato di seguito (è verificato per 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
come con le altre soluzioni anche con FF 24.4 il codice sopra riportato non funziona quando esistono larghezze dei bordi come parte del layout di posizionamento.
rapina

Sei un salvavita. Sto lavorando ad alcuni bug GWT piuttosto profondi in questo momento e lanciare questo in un metodo JSNI risolve tutti i miei problemi !!
Will Byrne,

35

Puoi aggiungere due proprietà per Element.prototypeottenere la parte superiore / sinistra di qualsiasi elemento.

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 );
    }
} );

Questo si chiama così:

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

Ecco una demo che confronta i risultati con jQuery offset().tope .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/


14
la modifica Element.prototypeè generalmente considerata una cattiva idea . Porta a un codice davvero difficile da mantenere. Inoltre, questo codice non tiene conto dello scorrimento.
Jared Forsyth,

23

Per recuperare la posizione relativa alla pagina in modo efficiente e senza utilizzare una funzione ricorsiva: (include anche 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;

Includere tutti gli importanti scrollTop / scrollLeft rende questa risposta un po 'più corretta.
scunliffe,

19

Che ne dici di qualcosa del genere, passando l'ID dell'elemento e restituirà la parte sinistra o superiore, possiamo anche combinarli:

1) trova a sinistra

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

2) trova la cima

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

o 3) trova sinistra e in alto insieme

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

Potresti essere meglio servito usando un framework JavaScript, che ha funzioni per restituire tali informazioni (e molto altro!) In modo indipendente dal browser. Eccone alcuni:

Con questi framework, potresti fare qualcosa del genere: $('id-of-img').top ottenere la coordinata y-pixel dell'immagine.


2
@Costa Usano tutti quel tipo di funzioni, sebbene si tratti di un campo in evoluzione, poiché browser diversi si conformano in modo diverso alle specifiche. Gran parte del codice si occupa di "riparare" cose che vanno male. Dovresti davvero guardare il codice sorgente.
Shalom Craimer,

18
@scraimer: jQuery e YUI NON sono framework !!! Queste sono biblioteche ! Non è lo stesso. Citando jquery.com : "jQuery è una libreria JavaScript veloce, piccola e ricca di funzionalità ." Citando yuilibrary.com (puoi vedere anche la parola "magica" nell'URL ...): "YUI è una libreria JavaScript e CSS gratuita e open source per la creazione di applicazioni web riccamente interattive".
Sk8erPeter

29
Quindi dovresti usare enormi librerie solo per questo semplice compito? Non necessario. Odio che ogni volta che voglio fare qualcosa con js, ottengo queste soluzioni jQuery. jQuery non è JS!
Opptatt Jobber,

1
@OpptattJobber Sono d'accordo ... JQuery non è JavaScript. Si basa su Javascript ma è un linguaggio di programmazione completamente diverso.
Nick Manning,

5
@NickManning Non è una nuova lingua, è un livello di astrazione per il DOM che elimina la necessità di scrivere soluzioni alternative di compatibilità e prestazioni direttamente nel codice. Se non usi jQuery, dovresti comunque usare qualche tipo di livello di astrazione.
ginman,

15

jQuery .offset () otterrà le coordinate correnti del primo elemento o imposterà le coordinate di ogni elemento, nel set di elementi corrispondenti, relativamente al documento.


Per qualche motivo non sta dando gli stessi risultati in IE rispetto ad altri browser. Penso che in IE stia dando una posizione rispetto alla finestra, quindi se scorri, otterrai risultati diversi in IE rispetto ad altri
Abdul Rahim Haddad,

1
offset () è confuso dallo zoom, almeno in Android Chrome, quindi è inutile. stackoverflow.com/a/11396681/1691517 mostra un modo tollerante allo zoom.
Timo Kähkönen,

10

Ho preso la risposta di @ meouw, aggiunto in clientLeft che consente il bordo e quindi creato tre versioni:

getAbsoluteOffsetFromBody - simile a quello di @ meouw, ottiene la posizione assoluta rispetto al corpo o all'elemento html del documento (a seconda della modalità di stranezza)

getAbsoluteOffsetFromGivenElement: restituisce la posizione assoluta relativa all'elemento specificato (relativeEl). Si noti che l'elemento specificato deve contenere l'elemento el, altrimenti si comporterà come getAbsoluteOffsetFromBody. Questo è utile se hai due elementi contenuti in un altro (noto) elemento (facoltativamente diversi nodi nella struttura dei nodi) e vuoi renderli nella stessa posizione.

getAbsoluteOffsetFromRelative: restituisce la posizione assoluta relativa al primo elemento padre con position: relative. Questo è simile a getAbsoluteOffsetFromGivenElement, per lo stesso motivo, ma andrà solo fino al primo elemento corrispondente.

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 };
}

Se i problemi persistono, in particolare quelli relativi allo scorrimento, potresti provare a consultare http://www.greywyvern.com/?post=331 - Ho notato almeno un pezzo di codice discutibile in getStyle che dovrebbe andare bene supponendo che i browser si comportino bene , ma non ho ancora testato il resto.


Interessante ... ma su Edge getAbsoluteOffsetFromBody (element) .top restituisce un valore diverso durante lo scorrimento, in Chrome rimane coerente durante lo scorrimento. Sembra che Edge si stia regolando con la posizione di scorrimento. Quando l'elemento viene fatto scorrere fuori dalla vista ottengo un valore negativo.
Norman,

getAbsoluteOffsetFromRelative ha reso la mia giornata, ho dovuto riprodurre la descrizione del bootstrap senza Javascript del bootstrap, mi ha aiutato molto.
Nolyurn,

Nel caso in cui Meouw cambi il loro nome utente, link per rispondere: stackoverflow.com/a/442474/3654837 . (Non voglio cancellare questo vecchio thread, quindi sì, ho inserito un commento)
Mukyuu,

8

se si utilizza jQuery, il plug-in dimensioni è eccellente e consente di specificare esattamente ciò che si desidera.

per esempio

Posizione relativa, posizione assoluta, posizione assoluta senza imbottitura, con imbottitura ...

Continua, diciamo solo che c'è molto che puoi farci.

Inoltre il vantaggio dell'utilizzo di jQuery è la sua dimensione di file leggera e un facile utilizzo, non tornerai a JavaScript senza di essa in seguito.


8

Questo è il miglior codice che sono riuscito a creare (funziona anche con iframe, a differenza di offset () di jQuery). Sembra che il webkit abbia un comportamento un po 'diverso.

Basato sul commento di 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 };
}

Nota che dovrai jQueryusare $.browser.webkit; Dovrai giocare con navigator.userAgentper fare lo stesso con pure JavaScript.
SP

2
$ .browser non è più disponibile nell'ultima versione di jQuery
Gus

purtroppo anche con FF 24.4 il codice sopra riportato non funziona quando esistono larghezze dei bordi come parte del layout di posizionamento.
derubare

8

Se stai usando jQuery, questa potrebbe essere una soluzione semplice:

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

8

Differenza tra piccolo e piccolo

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 };
}

Guarda un esempio di coordinate: http://javascript.info/tutorial/coordinates


Questo purtroppo non funziona per tutti gli elementi che si potrebbero trovare all'interno di un moderno documento HTML. Embedded <svg>elementi, per esempio, non hanno offsetLeft, offsetTope offsetParentle proprietà.
Jonathan Eunice,

È giusto DIVo IMGno SVG. Visualizza "Guarda un esempio di coordinate"? puoi trovare l'oggetto svg è posizione chiamata getOffsetRect , prova a dipendere dal lavoro dell'oggetto.
KingRider,

7

L'approccio più pulito che ho trovato è una versione semplificata della tecnica utilizzata da jQuery offset. Simile ad alcune delle altre risposte con cui inizia getBoundingClientRect; quindi usa il windowe il documentElementper regolare la posizione di scorrimento così come cose come il margine sul body(spesso predefinito).

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

Mentre è molto probabile che questo si perda in fondo a così tante risposte, le migliori soluzioni qui non funzionavano per me.
Per quanto ne so, nessuna delle altre risposte avrebbe aiutato.

Situazione :
in una pagina HTML5 avevo un menu che era un elemento nav all'interno di un'intestazione (non l'intestazione THE ma un'intestazione in un altro elemento).
Volevo che la navigazione rimanesse in alto una volta che l'utente lo scorreva, ma prima di ciò l'intestazione era posizionata in modo assoluto (quindi avrei potuto sovrapporla leggermente qualcos'altro).
Le soluzioni sopra non hanno mai innescato un cambiamento perché .offsetTop non cambierà poiché si trattava di un elemento posizionato in modo assoluto. Inoltre, la proprietà .scrollTop era semplicemente la parte superiore dell'elemento più in alto ... vale a dire 0 e sarebbe sempre 0.
Qualsiasi test che ho eseguito utilizzando questi due (e lo stesso con i risultati getBoundingClientRect) non mi direbbe se la parte superiore della barra di navigazione è mai stata spostata in cima alla pagina visualizzabile (di nuovo, come riportato nella console, sono rimasti semplicemente gli stessi numeri durante lo scorrimento si è verificato).

Soluzione
La soluzione per me stava utilizzando

window.visualViewport.pageTop

Il valore della proprietà pageTop riflette la sezione visualizzabile dello schermo, quindi mi permette di tracciare dove un elemento è in riferimento ai confini dell'area visualizzabile.

Probabilmente non è necessario dirlo, ogni volta che ho a che fare con lo scorrimento, mi aspetto di utilizzare questa soluzione per rispondere programmaticamente al movimento degli elementi sottoposti a scorrimento.
Spero che aiuti qualcun altro.
NOTA IMPORTANTE: questo sembra funzionare su Chrome e Opera attualmente e sicuramente non su Firefox (6-2018) ... fino a quando Firefox non supporta VisualViewport, consiglio di NON utilizzare questo metodo (e spero che lo facciano presto ... fa molto più senso del resto).


AGGIORNAMENTO:
solo una nota relativa a questa soluzione.
Mentre trovo ancora ciò che ho scoperto essere molto prezioso per le situazioni in cui "... rispondono programmaticamente al movimento degli elementi che vengono fatti scorrere". è applicabile. La soluzione migliore per il problema che avevo era usare CSS per impostare posizione: appiccicososull'elemento. Usando sticky puoi avere un elemento rimanere in alto senza usare javascript (NOTA: ci sono volte che questo non funzionerà in modo efficace come cambiare l'elemento in fixed ma per la maggior parte degli usi l'approccio sticky sarà probabilmente superiore)

UPDATE01:
Quindi ho capito che per una pagina diversa avevo un requisito in cui dovevo rilevare la posizione di un elemento in una configurazione a scorrimento leggermente complessa (parallasse più elementi che scorrono come parte di un messaggio). Mi sono reso conto in quello scenario che quanto segue forniva il valore che ho usato per determinare quando fare qualcosa:

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

Spero che questa risposta sia ora molto più utile.


è molto probabile che questo sia in cima a così tante risposte quando fai clic su attivo per ordinare le risposte
lucchi

@lucchi: D bene suppongo di poter rimuovere il testo @ the top ... anche se mi sono appena ripreso su questo e mi sono reso conto che avevo trovato una soluzione migliore per il mio problema ... anche se la mia risposta è più di un nota a piè di pagina per le risposte più complete. Sospetto che i miei requisiti non fossero forse così comuni che le altre risposte non funzionavano per me?
MER

1
Apprezzo comunque la tua risposta, è stato solo per dirti che, chiunque lo desideri sarà consapevole che hai scritto qualcosa di nuovo. Non sei solo ....
Lucchi,

5

L'ho fatto così, quindi era compatibile con i vecchi browser.

// 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;
    }

Maggiori informazioni sulle coordinate in JavaScript qui: http://javascript.info/tutorial/coordinates


4

Per ottenere l'offset totale di un elemento, è possibile riassumere ricorsivamente tutti gli offset padre:

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

con questa funzione di utilità l'offset superiore totale di un elemento 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;
}

Grazie a ThinkingStiff per la risposta , questa è solo un'altra versione.


2

Ho usato con successo la soluzione di Andy E per posizionare un bootstrap 2 modale a seconda del collegamento in una riga della tabella su cui un utente fa clic. La pagina è una pagina di Tapestry 5 e javascript di seguito viene importato nella classe di pagine 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);

}

Il mio codice modale:

<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>

Il collegamento nel ciclo:

<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>

E il codice java nella classe di pagina:

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');");
        }
    });
}

Spero che questo aiuti qualcuno, questo post ha aiutato.


Questo codice js mi ha aiutato, ho una vecchia app webforms che utilizza più segnaposto per iniettare pagine aspx e non sono riuscito a capire come aggiungereChild () di una finestra popup che stavo creando per inserirlo nella finestra perché l'intero albero DOM è distrutto con più segnaposto e markup errato. Usando body.getBoundingClientRect () e poi usando il suo posizionamento migliore era quello di cui avevo bisogno. Grazie.
Brad Martin,

1

Dopo molte ricerche e prove questo sembra funzionare

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 };
}

vedi http://jsbin.com/xuvovalifo/edit?html,js,output


1

Ho pensato di buttare anche questo.
Non sono stato in grado di testarlo nei browser più vecchi, ma funziona con l'ultimo dei primi 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

Dal momento che browser diversi rendono il bordo, il riempimento, il margine e così via in modo diverso. Ho scritto una piccola funzione per recuperare le posizioni superiore e sinistra dell'elemento specifico in ogni elemento radice che desideri in una dimensione precisa:

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

Per recuperare la posizione sinistra è necessario restituire:

    return offsetRect.left - rootRect.left;

-1

Ottieni la posizione del div rispetto a sinistra e in alto

  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 

Ho votato verso il basso perché in basso e a destra non sono proprietà di offset ()
MacroMan

@MacroMan, rispetto la tua decisione ma ho già spiegato nel testo che "il codice in basso a destra non è testato". Inoltre, aggiornerò il mio codice molto presto.
Vishal,

Penso che sia el.offsetTope el.offsetLeft(l'OP non dice nulla su jQuery ... Non sono sicuro del perché la tua risposta usi neanche jQuery ...)
mesqueeb
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.