2012-08-23 7 views
6

Ho il seguente:cadere solo all'elemento che si vede

Sto cercando di impostarlo in modo che quando si trascinare la voce, solo viene scartato all'elemento div, che si può vedere, e è non coperto.

Così ho usato questo js:

$(".draggable").draggable({ 
    helper: "clone" 
}) 
$("#bottom, .draggable").droppable({ 
    drop: function(event, ui) { 
     var $this = $(this), 
      $dragged = $(ui.draggable); 
     $this.append($dragged.clone()); 
    }, 
    hoverClass: "dragHover" 
})​ 

Ma cade l'elemento in entrambi i luoghi anche se solo una delle aree di rilascio non è visibile!

Come faccio a risolvere il problema in modo che ciò avvenga non?

Fiddle: http://jsfiddle.net/maniator/Wp4LU/


Extra Info per ricreare la pagina di senza il violino:

HTML:

<div id="top"> 
    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 

    <div class="draggable"> 
     Lorem ipsum dolor sit amet 
    </div> 
    </div> 

    <div id="bottom"></div> 

CSS:

.draggable { 
    border: 1px solid green; 
    background: white; 
    padding: 5px; 
} 

.dragHover{ 
    background: blue; 
} 

#top { 
    height: 500px; 
    overflow-y: scroll; 
} 
#bottom { 
    height: 150px; 
    overflow-y: scroll; 
    border: red solid 4px; 
} 

+0

Poiché non ha risolto il problema nel server live, ecco un [fiddle] (http://jsfiddle.net/ult_combo/Wp4LU/18/) che utilizza la proprietà disabilitata per simulare un 'event.stopImmediatePropagation' a altri widget dell'interfaccia utente, si spera che possa essere migliorato se non viene trovato un modo migliore. –

+0

@Neal Non pensi che possiamo usare un propert jquery come $ this.is (": visible"). Non so molto di jquery ma si può dire che questo è un tentativo da un principiante – Moons

risposta

2

Provare a impostare con la funzione accept. The working demo.

$("#bottom, .draggable").droppable({ 
    drop: function(event, ui) { 
     var $this = $(this), 
      $dragged = $(ui.draggable); 
     $this.append($dragged.clone()); 
    }, 
    accept: function() { 
     var $this = $(this), divTop= $("#top"); 
     if ($this.is(".draggable")) { 
      return $this.offset().top < divTop.offset().top + divTop.height() ; 
     } 
     return true; 
    }, 
    hoverClass: "dragHover" 
})​;​ 
+0

Holy awesomeness^_^questo sembra funzionare :-). Devo testarlo un po 'di più MrGreen. Grazie mille! – Neal

2

Se ho avuto ragione - questo dovrebbe risolvere il problema - http://jsfiddle.net/Wp4LU/60/ Inoltre si potrebbe scrivere su misura accetti Funzione - http://jqueryui.com/demos/droppable/#option-accept

Codice:

var draggableList = $('#top'); 

$(".draggable").draggable({ 
    helper: "clone" 
}); 
$("#bottom, .draggable").droppable({ 
    drop: function(event, ui) { 
     var $this = $(this), 
      $dragged = $(ui.draggable); 

     if ($this.hasClass("draggable")) { 
      if ($this.position().top >= draggableList.height() || 
       $this.position().top + $this.outerHeight() >= 
       draggableList.height()) 
       return; 
     } 

     $this.append($dragged.clone()); 
    }, 
    hoverClass: "dragHover" 
})​;​ 
+0

Questo funziona bene nel violino ... ma non sembra funzionare nel mio codice reale (che sembra leggermente diverso) .... – Neal

0

Secondo le fonti (jquery.ui.droppable.js), l'operazione di rilascio cercherà tutti i file trascinabili idonei e applicherà la funzione di rilascio a tutti quelli che si intersecano con esso:

drop: function(draggable, event) { 

    var dropped = false; 
    $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { 

     if(!this.options) return; 
     if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) 
      dropped = this._drop.call(this, event) || dropped; 

(Le versioni precedenti avevano l'ultima condizione "OR" invertita, quindi si applica solo a un singolo trascinabile. Prova il tuo violino con jQuery 1.5.2/jQuery UI 1.8.9, e vedi che cade solo su un elemento, anche se "sbagliato" ...)

E ogni modalità di tolleranza attualmente implementata solo nella funzione $.ui.intersect tener conto della (x, y) coordinate:

switch (toleranceMode) { 
    case 'fit': 
     return (l <= x1 && x2 <= r 
      && t <= y1 && y2 <= b); 
     break; 
    case 'intersect': 
     return (l < x1 + (draggable.helperProportions.width/2) // Right Half 
      && x2 - (draggable.helperProportions.width/2) < r // Left Half 
      && t < y1 + (draggable.helperProportions.height/2) // Bottom Half 
      && y2 - (draggable.helperProportions.height/2) < b); // Top Half 
     break; 
    ... 

Quindi, a meno che qualcuno aggiunge una modalità di tolleranza consapevoli z-index, l'unica opzione è quella di risolvere il problema in qualche modo. Io suggerirei prima di aggiungere ogni candidato droppable per un set e, quando è il momento di abbandonare, selezionare solo quello che è "più vicino" alla schermata:

$("#bottom, .draggable").droppable({ 
    over: function(event, ui) { 
     if (!ui.draggable.data("drop-candidates")) 
      ui.draggable.data("drop-candidates",[]); 
     ui.draggable.data("drop-candidates").push(this); 
    }, 
    out: function(event, ui) { 
     var that = this, 
      candidates = ui.draggable.data("drop-candidates") || []; 
     ui.draggable.data("drop-candidates", $.grep(candidates, function(e) { 
      return e != that; 
     }); 
    }, 
    drop: function(event, ui) { 
     var $this = $(this), 
      $dragged = $(ui.draggable); 
     var candidates = $.data("drop-candidates").sort(closestToScreen); 
     if (candidates[0] == this) 
      $this.append($dragged.clone()); 
    }, 
    hoverClass: "dragHover" 
})​ 

Ora, l'attuazione della closestToScreen comparatore è la parte difficile . Lo W3C CSS Specification descrive come i motori di rendering dovrebbero ordinare gli elementi da dipingere, ma non sono stato in grado di trovare un modo semplice per accedere a queste informazioni. Ho anche asked this question qui a SO, forse qualcuno troverà una buona strada.


P.S. Se la modifica della fonte jQuery UI è un'opzione, si potrebbe provare l'implementazione di una modalità di tolleranza consapevoli z-index utilizzando document.getElementFromPoint, come this answer a detta domanda suggerito:

var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, 
    y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; 
switch (toleranceMode) { 
    ... 
    case 'z-index-aware': 
     return document.elementFromPoint(x1,y1) == droppable; 
     break; 

(che garantisca solo l'elemento giusto sotto l'angolo in alto a sinistra del draggable sarebbe considerato "abbastanza buono" come obiettivo di caduta - non ideale, ma migliore di quello che abbiamo finora - una soluzione simile potrebbe essere adattata per utilizzare invece le coordinate del puntatore del mouse)

E, no, non è possibile utilizzare questo metodo con la soluzione alternativa presentata in precedenza: al momento della caduta, l'helper è l'elemento più vicino allo schermo ... (Modifica: d'oh! Non funzionerebbe nemmeno se implementato come modalità di tolleranza, per lo stesso motivo ...)

0

Se si vuole solo far cadere l'elemento si può vedere si potrebbe cambiare il vostro selettore:

$(".draggable:visible").draggable({ 
    helper: "clone" 
}); 
$("#bottom, .draggable:visible").droppable({ 
    drop: function(event, ui) { 
     var $this = $(this), 
      $dragged = $(ui.draggable); 
     $this.append($dragged.clone()); 
    }, 
    hoverClass: "dragHover" 
})​; 

O quando si nasconde un elemento cambiare la sua classe trascinabili da qualcosa altro.

+0

Questo non funzionerà ... l'evento è ** non ** delegato .... – Neal

+0

@Neal sembra che non ho avuto il vero problema qui allora. sembra che tu abbia ricevuto la tua risposta da un altro post. in bocca al lupo – TecHunter

Problemi correlati