jQuery arrastrable muestra el ayudante en el lugar incorrecto después de que la página se desplaza


79

Estoy usando jQuery que se puede arrastrar y soltar para un sistema de planificación del trabajo que estoy desarrollando. Los usuarios arrastran trabajos a un día o usuario diferente, y luego los datos se actualizan mediante una llamada ajax.

Todo funciona bien, excepto cuando me desplazo hacia abajo en la página principal (los trabajos aparecen en un planificador semanal grande que excede la parte inferior de la ventana de mi navegador). Si intento arrastrar un elemento que se puede arrastrar aquí, el elemento aparece sobre el cursor del mouse con la misma cantidad de píxeles que he desplazado hacia abajo. El estado de desplazamiento sigue funcionando bien y la funcionalidad está funcionando pero no se ve bien.

Estoy usando jQuery 1.6.0 y jQuery UI 1.8.12.

Estoy seguro de que necesito agregar una función de compensación, pero no sé dónde aplicarla o si hay una manera mejor. Aquí está mi .draggable()código de inicialización:

$('.job').draggable({
  zIndex: 20,
  revert: 'invalid',
  helper: 'original',
  distance: 30,
  refreshPositions: true,
});

¿Alguna idea de lo que puedo hacer para solucionar este problema?


¿Puede proporcionar una demostración de trabajo
jimy

@jimy es todo dinámico y muy seguro, así que tendría que escribir un ejemplo completamente nuevo; Lo haré si nadie tiene una respuesta rápida lo antes posible.
Alex

¿Puede publicar todas las propiedades css que tiene o hereda su arrastrable?
DarthJDG

2
Según mi respuesta más abajo, esto parece estar finalmente solucionado
Patrick

Respuestas:


107

Este podría ser un informe de error relacionado, existe desde hace bastante tiempo: http://bugs.jqueryui.com/ticket/3740

Parece suceder en todos los navegadores que probé (Chrome, FF4, IE9). Hay varias formas de solucionar este problema:

1. Úselo position:absolute;en su css. Los elementos absolutamente posicionados no parecen verse afectados.

2. Asegúrese de que el elemento padre (evento si es el cuerpo) se haya overflow:auto;establecido. Mi prueba mostró que esta solución corrige la posición, pero deshabilita la función de desplazamiento automático. Aún puede desplazarse usando la rueda del mouse o las teclas de flecha.

3. Aplique manualmente la corrección sugerida en el informe de error anterior y pruebe a fondo si causa otros problemas.

4. Espere una solución oficial. Está programado para jQuery UI 1.9, aunque se ha pospuesto varias veces en el pasado.

5. Si está seguro de que sucede en todos los navegadores, puede poner estos trucos en los eventos de los draggables afectados para corregir los cálculos. Sin embargo, hay muchos navegadores diferentes para probar, por lo que solo debe usarse como último recurso:

$('.drag').draggable({
   scroll:true,
   start: function(){
      $(this).data("startingScrollTop",$(this).parent().scrollTop());
   },
   drag: function(event,ui){
      var st = parseInt($(this).data("startingScrollTop"));
      ui.position.top -= $(this).parent().scrollTop() - st;
   }
});

12
¡Eso es genial, Gracias! (Desbordamiento de configuración: se corrigió automáticamente de inmediato. Apliqué el estilo a las celdas de la tabla individual.
Alex

2
jsfiddle.net/a2hzt/5 overflow-y: desplazarse por el elemento html también crea este problema en Firefox (Chrome funciona), simplemente desplácese hacia abajo e intente arrastrar.
digitalPBK

8
Es una mierda, por helper: "clone". bugs.jqueryui.com/ticket/9315 Nivel bloqueador , un punto por encima importante. tj.vantoll dice "6 arreglos arrastrables que aterrizaron en 1.10.3 podrían ser sospechosos". El ejemplo más simple hasta ahora: jsfiddle.net/7AxXE
Bob Stein

7
Confirmado, este error está en jQuery UI 1.10.3 pero no 1.10.2
Bob Stein

2
Parece que el problema también existe en jQuery UI 1.10.4 . ¡Me limitaré a 1.10.2 por ahora!
lhan

45

Esta solución funciona sin ajustar el posicionamiento de nada, simplemente clona el elemento y lo coloca absolutamente posicionado.

$(".sidebar_container").sortable({
  ..
  helper: function(event, ui){
    var $clone =  $(ui).clone();
    $clone .css('position','absolute');
    return $clone.get(0);
  },
  ...
});

El ayudante puede ser una función que necesita devolver el elemento DOM para arrastrar.


+1 Muchas gracias, esto me funciona con sortable (estaba a punto de probar algo similar pero menos elegante). ¡Sin embargo, tienes un pequeño error tipográfico con $ j! :)
Iain Collins

4
Para mí: arrastrar no funciona en absoluto con esto y devuelve errores: TypeError: this.offsetParent [0] no está definido
ProblemsOfSumit

Creo que es ui.helper no solo ui
Mohammed Joraid

1
Gracias por ayudarme con Sortable
BG BRUNO

1
Esta es la única respuesta que me funciona y es la más sencilla de implementar. Gran solución
Brett Gregson

11

Esto funcionó para mí:

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},

arreglar mi problema"1.11.0"
Зелёный

Esa es una solución divertida, pero solo funcionará en navegadores que tengan el error (Chrome). Los navegadores que no tienen el error ahora lo tendrán pero invertido :)
manu

Nota: algunos analizadores JS pueden quejarse de "falta de base" al utilizar esta solución. Para solucionarlo, reemplace var st = parseInt ($ (this) .data ("beginScrollTop")); con var st = parseInt ($ (esto) .data ("startScrollTop"), 10); (es decir, proporcione el sistema numérico que se utilizará). 10 es el predeterminado, pero algunos analizadores pueden requerir que esto esté presente sin embargo (por ejemplo, paquete web)
ripper17

7

Perdón por escribir otra respuesta. Como no pude usar ninguna de las soluciones en la respuesta anterior, busqué mucho en Google e hice muchas ediciones menores frustrantes antes de encontrar otra solución razonable.

Este problema parece ocurrir siempre que cualquiera de los elementos principales se haya positionestablecido en 'relativo'. Tuve que reorganizar mi marcado y alterar mi CSS, pero al eliminar esta propiedad de todos los padres, pude empezar a .sortable()trabajar correctamente en todos los navegadores.


Lo mismo para mí aquí. Cualquiera position: relative;en cualquier padre hace que esto suceda.
wojtiku

totalmente de acuerdo! Para mí, era sólo un estilo en línea en el cuerpo con position: relative;el cual tuvo que ser retirado .. elementos primarios entre los que pueden arrastrarse y el cuerpo parece no hacer problemes aquí ..
con

1
Dios mío, eso fue todo gracias, garrr ¿por qué la gente no usa Dragula en estos tiempos? ¡Gracias!
Domingo

Muchas gracias! Padre de padre que tiene posición: pariente lo causó por mí
wjk2a1

7

Parece que este error aparece muy a menudo y cada vez hay una solución diferente. Nada de lo anterior, o cualquier otra cosa que encontré en Internet, funcionó. Estoy usando jQuery 1.9.1 y Jquery UI 1.10.3. Así es como lo arreglé:

$(".dragme").draggable({
  appendTo: "body",
  helper: "clone",
  scroll: false,
  cursorAt: {left: 5, top: 5},
  start: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  },
  drag: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  }
});

Funciona en FF, IE, Chrome, todavía no lo he probado en otros navegadores.


1
esto funcionó para mí, excepto que tuve que usar ui.offset.top en lugar de ui.position.top
c.dunlap

5

Borro el desbordamiento:

html {overflow-y: scroll; background: #fff;}

¡Y funciona perfectamente!


5

Este error se movió a http://bugs.jqueryui.com/ticket/6817 y, a partir de hace unos 5 días (16 de diciembre de 2013 o aproximadamente) parece que finalmente se ha solucionado. La sugerencia en este momento es usar la última compilación de desarrollo de http://code.jquery.com/ui/jquery-ui-git.js o esperar la versión 1.10.4 que debería contener esta corrección .

Editar: Parece que esta solución ahora podría ser parte de http://bugs.jqueryui.com/ticket/9315 que no está programado para eliminarse hasta la versión 1.11. El uso de la versión de control de fuente vinculada anterior de jQuery parece solucionar el problema para mí y @Scott Alexander (comentario a continuación).


Estoy usando 1.10.4 y el error sigue ahí, aunque usé ese enlace y todo funciona bien.
Scott Alexander

@ScottAlexander Es posible que la solución se haya adjuntado a un ticket diferente al que pensaba. Edité mi respuesta basándome en eso. ¡Gracias!
Patrick

4

Parece notable que este error no se haya solucionado durante tanto tiempo. Para mí es un problema en Safari y Chrome (es decir, los navegadores webkit) pero no en IE7 / 8/9 ni en Firefox, que funcionan bien.

Encontré que la configuración absoluta o fija, con o sin! Importante, no ayudó, así que al final agregué una línea a mi función de controlador de arrastre:

ui.position.top += $( 'body' ).scrollTop();

Esperaba tener que hacer esa línea específica de webkit, pero curiosamente funcionó bien en todas partes. (Espere un comentario mío pronto diciendo 'er no, en realidad arruinó todos los demás navegadores').


1
Esto funciona, pero cuando se desplaza mientras arrastra, aún cambia la posición y. La solución número 5 de DarthJDG también funciona cuando se desplaza mientras se arrastra.
mirelon

3

lo que he hecho es:

$("#btnPageBreak").draggable(
        {
          appendTo: 'body',
          helper: function(event) {
            return '<div id="pageBreakHelper"><img  id="page-break-img"  src="page_break_cursor_red.png" /></div>';
          },
          start: function(event, ui) {
          },
          stop: function(event, ui) {
          },
          drag: function(event,ui){
            ui.helper.offset(ui.position);
         }
        });

1

No estoy completamente seguro de que esto funcione en todos los casos, pero esta solución simplemente funcionó para mí en todas las situaciones que tuve que probar (y donde las soluciones propuestas anteriores dadas aquí y en otros lugares fallaron)

(function($){
$.ui.draggable.prototype._getRelativeOffset = function()
{
    if(this.cssPosition == "relative") {
        var p = this.element.position();
        return {
            top: p.top - (parseInt(this.helper.css("top"),10) || 0)/* + this.scrollParent.scrollTop()*/,
            left: p.left - (parseInt(this.helper.css("left"),10) || 0)/* + this.scrollParent.scrollLeft()*/
        };
    } else {
        return { top: 0, left: 0 };
    }
};
}(jQuery));

(Lo envié al rastreador jQuery.ui para ver qué piensan al respecto ... sería genial si ese error de 4 años pudiera finalmente corregirse: /)


1

Estoy usando JQuery arrastrable en Firefox 21.0 y estoy teniendo el mismo problema. El cursor permanece una pulgada por encima de la imagen de ayuda. Creo que este es un problema en el propio Jquery que aún no se ha resuelto. Encontré una solución a este problema, que está usando la propiedad "cursorAt" del draggable. Lo usé de la siguiente manera, pero uno puede cambiar esto de acuerdo con sus requisitos.

$('.dragme').draggable({
helper: 'clone',    
cursor: 'move',    
cursorAt: {left: 50, top: 80}
});

Nota: Esto se aplicará a todos los navegadores, por lo que después de usar este código, verifique su página en todos los navegadores para obtener las posiciones izquierda y superior correctas.


1

Esto es lo que me funcionó, después de adaptar todo lo que he leído sobre el problema.

$(this).draggable({
  ...
  start: function (event, ui) {
    $(this).data("scrollposTop", $('#elementThatScrolls').scrollTop();
    $(this).data("scrollposLeft", $('#elementThatScrolls').scrollLeft();
  },
  drag: function (event, ui) {
    ui.position.top += $('#elementThatScrolls').scrollTop();
    ui.position.left += $('#elementThatScrolls').scrollLeft();
  },
  ...
}); 

* elementThatScrolls es el padre o el antepasado con overflow: auto;

Calcula la posición del elemento de desplazamiento y se suma a la posición del ayudante cada vez que se mueve / arrastra.

Espero que ayude a alguien, ya que perdí mucho tiempo en esto.


1

Esto parece hacer la solución sin necesidad de usar la posición: absoluta en el padre :)

$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});

¡Gracias! esto es lo único que funcionó para mí. (No estoy seguro de entender el problema ... mi problema es que arrastrar, arrastrar el desplazamiento funciona bien cuando el arrastre comienza con la barra de desplazamiento en la parte superior. Si la barra de desplazamiento comienza más abajo, entonces tengo un problema de desplazamiento)
John Smith

1

Me las arreglé para solucionar el mismo problema al agregar display: inline-block a los arrastrados

Agregar position: relativeNO funcionó para mí (jQuery lo anula conposition: absolute el inicio de arrastre)

Versiones jQuery usadas:

  • jQuery - 1.7.2
  • Interfaz de usuario de jQuery - 1.11.4

position: relativepuede haber funcionado si lo movió a un elemento contenedor de nivel superior. Sé que no ayuda ahora, pero solo como referencia y tal vez para un futuro desarrollador con problemas.
gdibble

1

Tuve el mismo problema y descubrí que todo esto se debía a una clase "navbar-fixed-top" de la barra de navegación de arranque con posición fija, que se mueve hacia abajo en mi <body>60px por debajo de<html> parte superior. Entonces, cuando estaba moviendo formularios que se pueden arrastrar en mi sitio, el cursor apareció 60px en la parte superior del formulario.

Puede ver que en la herramienta de depuración de Chrome, en la interfaz de Elementos, haga clic en el <body> etiqueta y verá un espacio entre la parte superior y el cuerpo.

Dado que estoy usando esta barra de navegación en todas mis aplicaciones y no quería modificar mi llamada de inicialización para arrastrar (según el procedimiento de DarthJDG) para cada formulario. Decidí extender el widget arrastrable de esta manera y simplemente agregar un yOffset en mi inicialización arrastrable.

(function($) {
  $.widget("my-ui.draggable", $.ui.draggable, {
    _mouseDrag: function(event, noPropagation) {

      //Compute the helpers position
      this.position = this._generatePosition(event);
      this.positionAbs = this._convertPositionTo("absolute");

      //Call plugins and callbacks and use the resulting position if something is returned
      if (!noPropagation) {
        var ui = this._uiHash();
        if(this._trigger('drag', event, ui) === false) {
          this._mouseUp({});
          return false;
        }
        this.position = ui.position;
      }
      // Modification here we add yoffset in options and calculation
      var yOffset = ("yOffset" in this.options) ? this.options.yOffset : 0;

      if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
      if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top-yOffset+'px';
      if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

      return false;
    }
  });
})(jQuery);

Ahora, cuando inicializo el elemento / formulario arrastrable en un sitio usando la barra de navegación de arranque:

// Make the edit forms draggable
$("#org_account_pop").draggable({handle:" .drag_handle", yOffset: 60});

Por supuesto, tendrá que experimentar para determinar el yOffset correcto según su propio sitio.

Gracias de todos modos a DarthJDG que me indicó la dirección correcta. ¡Salud!


0

Dejé de usar jQueryUi arrastrable y me mudé para usar un mejor complemento llamado jquery.even.drag , un tamaño de código mucho más pequeño, sin toda la basura que tiene jQueryUI.

Hice una página de demostración usando este complemento dentro de un contenedor que tiene una posición: fija

Manifestación

Espero que esto ayude a alguien, porque este problema es GRANDE.


0

Tuve un problema similar, solo que con IE 10 en particular ejecutándose en Windows 8. Todos los demás navegadores funcionaron bien. Quitar cursorAt: {top: 0} resolvió el problema.


0

Probé varias respuestas aquí, incluida la actualización de jQuery y descubrí que esto funcionó para mí. Probé esto en los últimos Chrome e IE. Supongo que esto será un problema con diferentes soluciones según el diseño de su interfaz de usuario.

$('{selector}').draggable({
    start: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    },
    drag: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    }
});

0

¿Por qué no tomar la posición del cursor? Estoy usando el complemento ordenable y lo soluciono con este código:

sort: function(e, ui) {
    $(".ui-sortable-handle.ui-sortable-helper").css({'top':e.pageY});
}

0

Utilice appendTo: "body'y establezca la posición con cursorAt. Esto funciona bien para mí.

Ejemplo de mi icono siguiendo el cursor del mouse incluso después de desplazarme por la página

$('.js-tire').draggable
      tolerance: 'fit',
      appendTo: 'body',
      cursor: 'move',
      cursorAt:
        top: 15,
        left: 18
      helper: (event) ->
        $('<div class="tire-icon"></div>').append($('<img src="/images/tyre_32_32.png" />'))
      start: (event, ui) ->
        if $(event.target).hasClass 'in-use'
          $('.js-send-to-maintenance-box').addClass 'is-highlighted'
        else
          $('.ui-droppable').addClass 'is-highlighted'
      stop: (event, ui) ->
        $('.ui-droppable')
          .removeClass 'is-highlighted'
          .removeClass 'is-dragover'

0

Estoy usando un navegador pegajoso en la parte superior y pensé que eso era lo que estaba causando el problema de desplazamiento que todos los demás parecen tener. Probé la idea de todos los demás con cursorAt, probé la contención y nada funcionó EXCEPTO desarmar mi desbordamiento de html en el CSS. Es una locura cómo un poco de CSS arruinará todo. Esto es lo que hice y funciona como un encanto:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
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.