Arrossegar i deixar anar en HTML5 (Drag & Drop HTML5)

Aquesta és una de les noves característiques afegides en HTML5, encara que ja es podia fer drag and drop mitjançant altres tècniques, ara a l’estar inclòs en HTML5 fa que “suposadament” funcioni en tots els navegadors encara que si no compleixen els estàndards com és el cas d’Internet Explorer et trobaràs en què en principi no funciona.

Per explicar aquestes noves funcionalitats em vaig a servir de 2 exemples senzills. En el primer veurem com arrossegar i deixar anar elements, clonar o eliminar-los, i en el segon un senzill puzle de 4 peces.

Perquè es pugui arrossegar i deixar anar un element calen dos tipus d’elements, un element arrastrable (que s’aconsegueix afegint al menys els atributs draggable = “true” i ondragstart = “la_funcion_que_sea (event)”) i un element en el qual es pugui deixar anar a què com el meu mínim cal posar ondragover = “return la_funcion_que_sea (event ) “i ondrop =” return la_funcion_que_sea (event) “.

exemple 1 d’arrossegar i deixar anar amb HTML5: arrossegar i deixar anar, clonar i eliminar elements

En el següent exemple els elements arrastrable1,2,3 i 4 són arrossegables i en els elements cuadro1,2,3 i paperera es poden deixar anar elements.

<!DOCTYPE html><html land="es"><head> <meta charset="utf-8" /> <title>Drag & drop</title> <link rel="stylesheet" type="text/css" href="estilo.css"> <script type="text/javascript"> //... </script></head><body> <header> <h1> Un ejemplo del uso de Drag & Drop en HTML5 </h1> </header> <section> <div ondragenter="return enter(event)" ondragover="return over(event)" ondragleave="return leave(event)" ondrop="return drop(event)"> <div class="cuadradito" draggable="true" ondragstart="start(event)" ondragend="end(event)"> 1 </div> <div class="cuadradito" draggable="true" ondragstart="start(event)" ondragend="end(event)"> 2 </div> <div class="cuadradito" draggable="true" ondragstart="start(event)" ondragend="end(event)"> 3 </div> </div> <div ondragenter="return enter(event)" ondragover="return over(event)" ondragleave="return leave(event)" ondrop="return drop(event)"> </div> <div ondragenter="return enter(event)" ondragover="return over(event)" ondragleave="return leave(event)" ondrop="return clonar(event)"> Clonadora </div> <div ondragenter="return enter(event)" ondragover="return over(event)" ondragleave="return leave(event)" ondrop="return eliminar(event)">Papelera</div> </section></body></html>

Anem a explicar breument perquè és cada atribut de l’element arrastrable:

  • draggable: si és true l’element es pot arrossegar, si és false o s’omet no es pot mo veure l’element.
  • ondragstart: Aquí s’indiqués l’acció que es portés a terme quan es comenci a arrossegar l’element.
  • ondragend: Aquí s’indiqués l’acció que es portés a terme quan es acabi d’arrossegar l’element (quan es deixi anar).

I per l’element a què es puguin arrossegar són aquests:

  • ondragenter: Aquí s’indiqués la acció que es portés a terme quan un element arrastrable entri dins l’element.
  • ondragover: Aquí s’indiqués l’acció que es portés a terme quan un element arrastrable aquest sobre l’element. En aquesta funció és on s’indica que elements arrossegables es poden deixar anar aquí.
  • ondragleave: Aquí s’indiqués l’acció que es portés a terme quan un element arrastrable deixi d’estar a sobre de l’element.
  • ondrop: Aquí s’indiqués l’acció que es portés a terme quan es deixi anar un element arrastrable sobre l’element.

Un cop vist quin és el codi HTML necessari per poder arrossegar i deixar anar elements anem a veure la part de javaScript. Comencem per les funcions de l’element arrastrable.

La primera acció que passa és la desencadenada dins ondragstart:

function start(e) { e.dataTransfer.effecAllowed = 'move'; // Define el efecto como mover e.dataTransfer.setData("Data", e.target.id); // Coje el elemento que se va a mover e.dataTransfer.setDragImage(e.target, 0, 0); // Define la imagen que se vera al ser arrastrado el elemento y por donde se coje el elemento que se va a mover (el raton aparece en la esquina sup_izq con 0,0) e.target.style.opacity = '0.4'; // Establece la opacidad del elemento que se va arrastrar}

En aquesta funció es defineix la manera en què es va a arrossegar l’element (none, copy, copyLink, copyMove, link, linkMove, move o all) en effecAllowed, s’estableix l’element que es va a arrossegar i la manera en què es va a guardar aquesta informació amb setData (format, element) i també es pot substituir la imatge de l’element quan es aquesta arrossegant per substituir la que el navegador fa servir per defecte (l’element amb cert grau de transparència) per la imatge (o l’element) indicada i les coordenades de l’element per les quals es arrossegués l’element. D’aquestes tres funcions només setData és obligatòria. A més d’aquestes funcions a la funció anterior també es modifica l’opacitat de l’element que s’arrossega perquè es vegi una mica transparent i es vegi millor l’element que s’està arrossegant.

Quan s’acaba d’arrossegar un element s’elimina la informació associada a l’element dataTransfer mitjançant setData amb el mètode clearData i com a a l’començar a arrossegar l’element es canvi l’opacitat de l’element es restaura al seu estat original.

function end(e) { e.target.style.opacity = ''; // Restaura la opacidad del elemento e.dataTransfer.clearData("Data");}

Ara veurem les funcions que s’executen quan es produeixen els esdeveniments de l’element contenidor:

les funcions que s’executen en els esdeveniments ondragenter i ondragleave es poden usar per exemple per canviar l’aspecte quan entra o surt un element arrastrable de l’element des del qual es diuen, en aquest exemple es posa una vora puntejat gris quan un element arrastrable passa per sobre i es treu la vora quan es surt.

function enter(e) { e.target.style.border = '3px dotted #555'; }function leave(e) { e.target.style.border = ''; }

Quan es col·loca un el emento arrastrable sobre un element en el qual es ‘pugui’ deixar anar s’executa l’esdeveniment ondragover des del qual es diu a la següent funció:

function over(e) { var elemArrastrable = e.dataTransfer.getData("Data"); // Elemento arrastrado var id = e.target.id; // Elemento sobre el que se arrastra // return false para que se pueda soltar if (id == 'cuadro1') { return false; // Cualquier elemento se puede soltar sobre el div destino 1 } if ((id == 'cuadro2') && (elemArrastrable != 'arrastrable3')) { return false; // En el cuadro2 se puede soltar cualquier elemento menos el elemento con id=arrastrable3 } if (id == 'cuadro3') { return false; } if (id == 'papelera') { return false; // Cualquier elemento se puede soltar en la papelera } }

El més important d’aquesta funció és el que retorna, si es pot deixar anar l’element retorna false (si, no és un error, torna false si es pot deixar anar) i true en cas contrari.

Per a indicar que elements es poden deixar anar i on es poden deixar anar en la línia 2 s’obté l’element que s’està arrossegant i en la 3 l’id de l’element sobre el que s’està arrossegant i combinant tots dos es pot aconseguir que no tots els elements es puguin deixar anar en tots els “contenidors”.

la següent funció permet que se situï l’element en la posició exacta en què es deixa anar. Amb les línies 2 i 3 l’element arrossegat ja estaria dins de l’element “contenidor”, però perquè es col·loqui en la posició exacta que vulguem cal usar posicionament absolut, de manera que hem de treure les coordenades en què s’ha deixat anar el element (línies 14 i 15), però si es deixa anar en una vora del “contenidor” pot ser que part de l’element arrossegat quedi fora de l’contenidor, el que no resulta molt estètic pel que són necessàries les coordenades de l’contenidor i la mida de l’ contenidor i de l’element arrossegat per saber si l’element queda fora o dins i si queda fora corregir la posició perquè quedi dins. (Només aquesta comprovat que no surti per la dreta i per baix perquè com a setDragImage les coordenades eren 0,0 no es pot sortir per dalt ni per l’esquerra.) En la darrera línia de la funció es restaura la vora a l’estat original que s’havia canviat en la funció enter.

function drop(e) { var elementoArrastrado = e.dataTransfer.getData("Data"); // Elemento arrastrado e.target.appendChild(document.getElementById(elementoArrastrado)); // Añade el elemento arrastrado al elemento desde el que se llama a esta funcion // Dimensiones del elemento sobre el que se arrastra tamContX = $('#'+e.target.id).width(); tamContY = $('#'+e.target.id).height(); // Dimensiones del elemento arrastrado tamElemX = $('#'+elementoArrastrado).width(); tamElemY = $('#'+elementoArrastrado).height(); // Posicion del elemento sobre el que se arrastra posXCont = $(e.target).position().left; posYCont = $(e.target).position().top; // Posicion absoluta del raton x = e.layerX; y = e.layerY; // Si parte del elemento que se quiere mover se queda fuera se cambia las coordenadas para que no sea asi if (posXCont + tamContX 

Amb arrossegar i deixar anar també es poden clonar elements d’una forma molt senzilla. A la primera línia s’obté l’element arrossegat per poder copiar-lo i en la següent es restaura l’opacitat perquè l’element clonat tingui l’opacitat original. Després es clona l’element i se li canvia el aneu a l’element clonat perquè sigui únic amb un nom i un comptador que serà una variable global (Una variable fora de les funcions) perquè no es repeteixi i s’afegeix a l’element des del qual es crida a aquesta funció (en el cas d’aquest exemple cuadro3).

function clonar(e) { var elementoArrastrado = document.getElementById(e.dataTransfer.getData("Data")); // Elemento arrastrado elementoArrastrado.style.opacity = ''; // Dejamos la opacidad a su estado anterior para copiar el elemento igual que era antes var movecarclone = elementoArrastrado.cloneNode(true); // Se clona el elemento movecarclone.id = "ElemClonado" + contador; // Se cambia el id porque tiene que ser unico contador += 1; elementoClonado.style.position = "static"; // Se posiciona de forma "normal" (Sino habria que cambiar las coordenadas de la posición) e.target.appendChild(movecarclone); // Se añade el elemento clonado e.target.style.border = ''; // Quita el borde del "cuadro clonador"}

I per acabar aquest exemple, anem amb el codi de la funció per eliminar elements arrossegables. Aquesta funció és molt simple, l’únic que cal tenir en compte és que per eliminar un element cal fer-ho des de la seva element pare però gràcies a l’ús de parentNode només es necessita l’element que es vol eliminar.

function eliminar(e) { var elementoArrastrado = document.getElementById(e.dataTransfer.getData("Data")); // Elemento arrastrado elementoArrastrado.parentNode.removeChild(elementoArrastrado); // Elimina el elemento e.target.style.border = ''; // Quita el borde}

Aquí pots veure en funcionament l’exemple complet:

veure the Pen exemple Drag & Drop en HTML5 by Ivan sales (@ isc7) on CodePen

exemple 2 d’arrossegar i deixar anar amb HTML5: Un puzle

Aquest exemple és bastant simple i sobretot si prèviament has vist l’exemple anterior en el qual es expliquen els diferents aspectes de l’drag & drop amb HTML5.

el codi és molt similar a el de l’exemple anterior, l’HTML és anàleg encara ja que en aquesta ocasió el objectiu és fer un puzle hi ha un contenidor inicial en què hi ha les peces de l’puzzle i un altre contenidor en el qual es farà el puzle que té quatre contenidors un per a cada peça.

I pel que fa a les funcions javaScript tampoc hi ha massa a comentar, únicament en la funció drop la primera línia ha de ser e.preventDefault (); per evitar que a l’deixar anar les peces que són imatges es produeixi l’acció per defecte de navegador (que s’haurà la imatge) i així funcioni tot com és d’esperar.

/** * Función que se ejecuta al arrastrar el elemento. */function start(e) { e.dataTransfer.effecAllowed = 'move'; // Define el efecto como mover (Es el por defecto) e.dataTransfer.setData("Text", e.target.id); // Coje el elemento que se va a mover e.target.style.opacity = '0.4';}/** * Función que se ejecuta se termina de arrastrar el elemento. */function end(e){ e.target.style.opacity = ''; // Restaura la opacidad del elemento e.dataTransfer.clearData("Data"); }/** * Función que se ejecuta cuando un elemento arrastrable entra en el elemento desde del que se llama. */function enter(e) { return true;}/** * Función que se ejecuta cuando un elemento arrastrable esta sobre el elemento desde del que se llama. * Devuelve false si el objeto se puede soltar en ese elemento y true en caso contrario. */function over(e) { if ((e.target.className == "contenedorPieza") || (e.target.id == "contenedorPiezas")) { return false; } else { return true; }} /** * Función que se ejecuta cuando un elemento arrastrable se suelta sobre el elemento desde del que se llama. */function drop(e) { e.preventDefault(); // Evita que se ejecute la accion por defecto del elemento soltado. var elementoArrastrado = e.dataTransfer.getData("Text"); e.target.appendChild(document.getElementById(elementoArrastrado)); // Coloca el elemento soltado sobre el elemento desde el que se llamo esta funcion comprobarPuzzle();}function comprobarPuzzle(){ if ((document.getElementById('pieza1').parentNode.id=='uno') && (document.getElementById('pieza2').parentNode.id=='dos') && (document.getElementById('pieza3').parentNode.id=='tres') && (document.getElementById('pieza4').parentNode.id=='cuatro')) { alert('Felicidades, has hecho un puzzle de 4 piezas xD'); }}

Per acabar comentar la funció comprobarPuzzle que simplement comprova si cada peça està en la seva posició i si és així ho indica amb un missatge. Aquesta funció cal cridar-la cada vegada que es col·loca una peça de manera que es crida des de la funció drop.

I finalment el puzle perquè el puguis veure:

Veure the Pen Trencaclosques drag & Drop HTML5 by Ivan Sales (@ isc7) on CodePen

Aquí pots descarregar el codi dels dos exemples.

4 Compartir

Leave a Comment

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *