Obtener la posición / desplazamiento del elemento en relación con un contenedor primario?


125

Estoy acostumbrado a trabajar con jQuery. Sin embargo, en mi proyecto actual uso zepto.js. Zepto no proporciona un position()método como lo hace jQuery. Zepto solo viene con offset().

¿Alguna idea de cómo puedo recuperar el desplazamiento de un contenedor en relación con un padre con js puro o con Zepto?


44
Vota abajo aceptando una respuesta jQuery (¡que ni siquiera está etiquetada como jQuery!) Al hacer una pregunta de JavaScript.
John

@John, ¿notaste la etiqueta zepto?
Supersharp

@Supersharp Use la JavaScriptetiqueta cuando use JavaScript puro. Si está utilizando un marco o biblioteca, entonces no utiliza la JavaScriptetiqueta. Si te llamas Jeff, no te llamaría Sally.
John

@John es una opinión, pero no es así como funciona SO. Por favor, lea la guía de etiquetas de JavaScript. En este caso, debe usarse junto con la etiqueta de la biblioteca.
Supersharp

@Supersharp Yeah SO es incompetente así; inflación literal de la etiqueta. 😒︎
John

Respuestas:


188

Advertencia: jQuery, no JavaScript estándar

element.offsetLefty element.offsetTopson las propiedades de javascript puro para encontrar la posición de un elemento con respecto a su offsetParent; siendo el elemento padre más cercano con una posición de relativeoabsolute

Alternativamente, siempre puede usar Zepto para obtener la posición de un elemento Y su padre, y simplemente restar los dos:

var childPos = obj.offset();
var parentPos = obj.parent().offset();
var childOffset = {
    top: childPos.top - parentPos.top,
    left: childPos.left - parentPos.left
}

Esto tiene el beneficio de darle el desplazamiento de un niño en relación con su padre, incluso si el padre no está posicionado.


9
Los elementos posicionados staticno son padres compensados.
Esailija

55
no use punto y coma dentro de llaves, use comas
Luca Borrione

1
¿Qué pasa con la posición fija? ¿Están compensados ​​los padres?
Ayyash

1
Sí, @ Ayya- la posición fija también crea un nuevo contexto de desplazamiento
mmmeff

9
@vsync jQuery no es el rey de nada desde que ie9 llegó a EOL en enero de 2016, tenemos una selección DOM estandarizada en todos los principales navegadores, aprenda js puro. Además, las opiniones sobre qué marco utilizar no tienen cabida en SO, ya que depende en gran medida del proyecto y la plataforma de destino.
Hans Koch

72

en js puro solo use offsetLefty offsetToppropiedades.
Violín de ejemplo: 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>


Gracias. ¿Existe también una manera de obtener el desplazamiento a un elemento parent.parent?
mate

2
p.offsetTop + p.parentNode.offsetTopPodría envolver esto en una llamada de función recursiva muy similar a PPK propuesto hace unos años. Podrías alterar la función para pasar el número de niveles a subir o usar un selector para imitar $(selector).parents(parentSelector). Preferiría esta solución porque la implementación de zepto solo funciona en los navegadores compatibles getBoundingClientsRect, lo que algunos móviles no.
Torsten Walter

Pensé que getBoundingClientsRecttenía un amplio respaldo ... si alguien sabe qué móviles no lo admiten, estaría interesado (no puedo encontrar ninguna tabla de soporte para móviles al respecto).
Nobita

Esta es probablemente la respuesta más correcta aunque no esté marcada. Mi solución personal estaba cambiando $(this).offset().lefta this.offsetLeft.
adjwilli

Esto también corrige el jQuery.position()comportamiento incorrecto dentro de un padre transformado en 3D, ¡muchas gracias!
rassoh

6

Lo hice así en 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;
};

=================== puedes llamarlo así

getWindowRelativeOffset(top, inputElement);

Me concentro en IE solo según mi enfoque, pero se pueden hacer cosas similares para otros navegadores.


1

Agregue el desplazamiento del evento al desplazamiento del elemento principal para obtener la posición de desplazamiento absoluto del evento.

Un ejemplo :

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;

    }
}

Cuando el destino del evento no es el elemento en el que se registró el evento, agrega el desplazamiento del padre al desplazamiento del evento actual para calcular el valor de desplazamiento "absoluto".

Según la API web de Mozilla: "La propiedad de solo lectura HTMLElement.offsetLeft devuelve el número de píxeles que la esquina superior izquierda del elemento actual está desplazada a la izquierda dentro del nodo HTMLElement.offsetParent " .

Esto ocurre principalmente cuando registra un evento en un elemento primario que contiene varios elementos secundarios más, por ejemplo: un botón con un ícono interno o un espacio de texto, un lielemento con tramos internos. etc ...


¿Qué pasa con el padre del padre? ¿Qué pasa con los elementos anidados que tienen barras de desplazamiento? ¿Qué pasa con los elementos anteriores con pantalla: ninguno? Una posición real de desplazamiento del documento es casi imposible de calcular, pero el motor de renderizado puede saberlo. Lástima que las propiedades simples como la posición del documento nunca se hayan incluido en DOM.
David Spector

@DavidSpector word

1

Ejemplo

Entonces, si tuviéramos un elemento hijo con una identificación de "elemento hijo" y quisiéramos obtener su posición izquierda / superior en relación con un elemento padre, digamos un div que tenía una clase de "elemento padre", tendríamos usa este código.

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position.top);

Complemento Finalmente, para el complemento real (con algunas notas que explican lo que está sucediendo):

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

Nota: Puede usar esto en mouseClick o mouseover Event

$(this).offsetRelative("div.item-parent");

No veo el desplazamiento explicado. Hay muchos casos extraños que pueden suceder.
David Spector

1

Tengo otra solución. Restar el valor de la propiedad principal del valor de la propiedad secundaria

$('child-div').offset().top - $('parent-div').offset().top;

0

Claro que es fácil con JS puro, solo haga esto, trabaje también para paneles HTML 5 fijos y animados, hice e intento este código y funciona para cualquier navegador (incluido 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>

¿Probó con todos los casos posibles de nodos principales y propiedades de elementos? ¿Tiene esto en cuenta el desplazamiento y el desplazamiento anidado?
David Spector
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.