Verwenden von jquery, um die Position des Elements relativ zum Ansichtsfenster abzurufen


117

Wie kann die Position eines Elements auf der Seite relativ zum Ansichtsfenster (und nicht zum Dokument) richtig ermittelt werden? jQuery.offsetFunktion schien vielversprechend:

Rufen Sie die aktuellen Koordinaten des ersten Elements ab oder legen Sie die Koordinaten jedes Elements in der Gruppe der übereinstimmenden Elemente relativ zum Dokument fest.

Aber das ist relativ zum Dokument. Gibt es eine äquivalente Methode, die Offsets relativ zum Ansichtsfenster zurückgibt?


5
HINWEIS: Siehe die Antwort von @Igor G ...
Carl Smith

3
Für DA sollten Sie die Antwort von Igor G wirklich als akzeptiert festlegen, es ist ein Lebensretter!
Vincent Duprez

Antworten:



287

Der einfachste Weg, die Größe und Position eines Elements zu bestimmen, besteht darin, seine Methode getBoundingClientRect () aufzurufen . Diese Methode gibt Elementpositionen in Ansichtsfensterkoordinaten zurück. Es erwartet keine Argumente und gibt ein Objekt mit den Eigenschaften left, right, top und bottom zurück . Die Eigenschaften links und oben geben die X- und Y-Koordinaten der oberen linken Ecke des Elements an, und die Eigenschaften rechts und unten geben die Koordinaten der unteren rechten Ecke an.

element.getBoundingClientRect(); // Get position in viewport coordinates

Überall unterstützt.


15
Es ist unglaublich, dass diese Methode von IE5 hinzugefügt wurde ... wenn etwas gut ist, ist es gut!
Roy Riojas

Dies schien zunächst großartig zu sein, berücksichtigt jedoch nicht, dass ein Benutzer auf Mobile Safari 7 zoomt.
Blick zoomt

2
Wird vom neuesten Firefox nicht unterstütztgetBoundingClientRect is not a function
Wird user007

2
@ user007 Ich bestätige, dass es vom neuesten Firefox unterstützt wird.
adriendenat

26
Tolle Antwort, und um es jquery zu machen, machen Sie es einfach so: $('#myElement')[0].getBoundingClientRect().top(oder jede andere Position)
Guillaume Arluison

40

Hier sind zwei Funktionen zum Abrufen der Seitenhöhe und der Bildlaufbeträge (x, y) ohne Verwendung des Plugins für (aufgeblähte) Abmessungen:

// getPageScroll() by quirksmode.com
function getPageScroll() {
    var xScroll, yScroll;
    if (self.pageYOffset) {
      yScroll = self.pageYOffset;
      xScroll = self.pageXOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {
      yScroll = document.documentElement.scrollTop;
      xScroll = document.documentElement.scrollLeft;
    } else if (document.body) {// all other Explorers
      yScroll = document.body.scrollTop;
      xScroll = document.body.scrollLeft;
    }
    return new Array(xScroll,yScroll)
}

// Adapted from getPageSize() by quirksmode.com
function getPageHeight() {
    var windowHeight
    if (self.innerHeight) { // all except Explorer
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowHeight = document.body.clientHeight;
    }
    return windowHeight
}

Das ist brilliant. Sehr hilfreich.
Jimmy

Warum haben Sie aus Neugier in diesem Fall die Eigenschaft "self" anstelle von window verwendet?
Dkugappi


23

jQuery.offsetmuss mit scrollTopund scrollLeftwie in diesem Diagramm gezeigt kombiniert werden:

Bildlauf im Ansichtsfenster und Elementversatz

Demo:

function getViewportOffset($e) {
  var $window = $(window),
    scrollLeft = $window.scrollLeft(),
    scrollTop = $window.scrollTop(),
    offset = $e.offset(),
    rect1 = { x1: scrollLeft, y1: scrollTop, x2: scrollLeft + $window.width(), y2: scrollTop + $window.height() },
    rect2 = { x1: offset.left, y1: offset.top, x2: offset.left + $e.width(), y2: offset.top + $e.height() };
  return {
    left: offset.left - scrollLeft,
    top: offset.top - scrollTop,
    insideViewport: rect1.x1 < rect2.x2 && rect1.x2 > rect2.x1 && rect1.y1 < rect2.y2 && rect1.y2 > rect2.y1
  };
}
$(window).on("load scroll resize", function() {
  var viewportOffset = getViewportOffset($("#element"));
  $("#log").text("left: " + viewportOffset.left + ", top: " + viewportOffset.top + ", insideViewport: " + viewportOffset.insideViewport);
});
body { margin: 0; padding: 0; width: 1600px; height: 2048px; background-color: #CCCCCC; }
#element { width: 384px; height: 384px; margin-top: 1088px; margin-left: 768px; background-color: #99CCFF; }
#log { position: fixed; left: 0; top: 0; font: medium monospace; background-color: #EEE8AA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<!-- scroll right and bottom to locate the blue square -->
<div id="element"></div>
<div id="log"></div>


2
Das hat bei mir sehr gut funktioniert, aber ich habe dies verwendet, um festzustellen, ob ein Tooltip außerhalb der Grenzen liegt. Daher habe
Jordanien

Dies ist auf jeden Fall die absolut richtige Antwort. Alle anderen haben Probleme abhängig von der Maus- / Bildlauf-Delta-Konfiguration, den Browsern, dem Objektstandort usw.
Pedro Ferreira

2

Hier ist eine Funktion, die die aktuelle Position eines Elements im Ansichtsfenster berechnet:

/**
 * Calculates the position of a given element within the viewport
 *
 * @param {string} obj jQuery object of the dom element to be monitored
 * @return {array} An array containing both X and Y positions as a number
 * ranging from 0 (under/right of viewport) to 1 (above/left of viewport)
 */
function visibility(obj) {
    var winw = jQuery(window).width(), winh = jQuery(window).height(),
        elw = obj.width(), elh = obj.height(),
        o = obj[0].getBoundingClientRect(),
        x1 = o.left - winw, x2 = o.left + elw,
        y1 = o.top - winh, y2 = o.top + elh;

    return [
        Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),
        Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))
    ];
}

Die Rückgabewerte werden wie folgt berechnet:

Verwendung:

visibility($('#example'));  // returns [0.3742887830933581, 0.6103752759381899]

Demo:

function visibility(obj) {var winw = jQuery(window).width(),winh = jQuery(window).height(),elw = obj.width(),
    elh = obj.height(), o = obj[0].getBoundingClientRect(),x1 = o.left - winw, x2 = o.left + elw, y1 = o.top - winh, y2 = o.top + elh; return [Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))];
}
setInterval(function() {
  res = visibility($('#block'));
  $('#x').text(Math.round(res[0] * 100) + '%');
  $('#y').text(Math.round(res[1] * 100) + '%');
}, 100);
#block { width: 100px; height: 100px; border: 1px solid red; background: yellow; top: 50%; left: 50%; position: relative;
} #container { background: #EFF0F1; height: 950px; width: 1800px; margin-top: -40%; margin-left: -40%; overflow: scroll; position: relative;
} #res { position: fixed; top: 0; z-index: 2; font-family: Verdana; background: #c0c0c0; line-height: .1em; padding: 0 .5em; font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="res">
  <p>X: <span id="x"></span></p>
  <p>Y: <span id="y"></span></p>
</div>
<div id="container"><div id="block"></div></div>


0

Ich habe festgestellt, dass die Antwort von cballou ab Januar 2014 in Firefox nicht mehr funktioniert. Insbesondere wurde if (self.pageYOffset)sie nicht ausgelöst, wenn der Client nach rechts 0gescrollt hatte, aber nicht nach unten - da es sich um eine False-Nummer handelt. Dies blieb eine Weile unentdeckt, da Firefox document.body.scrollLeft/ unterstützte Top, aber dies funktioniert bei mir nicht mehr (unter Firefox 26.0).

Hier ist meine modifizierte Lösung:

var getPageScroll = function(document_el, window_el) {
  var xScroll = 0, yScroll = 0;
  if (window_el.pageYOffset !== undefined) {
    yScroll = window_el.pageYOffset;
    xScroll = window_el.pageXOffset;
  } else if (document_el.documentElement !== undefined && document_el.documentElement.scrollTop) {
    yScroll = document_el.documentElement.scrollTop;
    xScroll = document_el.documentElement.scrollLeft;
  } else if (document_el.body !== undefined) {// all other Explorers
    yScroll = document_el.body.scrollTop;
    xScroll = document_el.body.scrollLeft;
  }
  return [xScroll,yScroll];
};

Getestet und funktionsfähig in FF26, Chrome 31, IE11. Funktioniert mit ziemlicher Sicherheit mit älteren Versionen von allen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.