JavaScript: drag and drop di file con le API HTML5

Short link

Il drag and drop è un'interazione che l'utente svolge trascinando e rilasciando gli elementi della pagina. Storicamente questo tipo di interazione era già disponibile in Internet Explorer 6, ma solo con HTML5 le API per il drag and drop sono state standardizzate.

Rendere gli elementi trascinabili

In HTML5 gli elementi che useranno il drag and drop vengono definiti come tali tramite l'attributo draggable:


<div id="test" draggable="true">Draggable Div</div>

Eventi del drag and drop

Ci sono diversi eventi DOM che gestiscono il drag and drop:

  • dragstart – Questo evento ha luogo quando un elemento comincia ad essere trascinato dall'utente. Non ha luogo quando un file viene trascinato nella finestra del browser.
  • drag – Questo evento continua ad essere attivo durante tutta la fase del trascinamento.
  • dragenter – Questo evento ha luogo quando l'elemento trascinato entra nell'elemento di destinazione. Il gestore di eventi deve essere impostato sull'elemento di destinazione.
  • dragleave – Questo evento ha luogo quando l'elemento trascinato lascia l'elemento di destinazione.
  • dragover – Questo evento continua ad essere attivo quando l'elemento trascinato è sopra l'elemento di destinazione.
  • drop – Questo evento ha luogo quando l'elemento trascinato o il file viene rilasciato.
  • dragend – Questo evento ha luogo quando il trascinamento di un elemento è stato completato.

Esempio:


const draggableElement = document.getElementById('test');
draggableElement.addEventListener('dragstart', e => { 
	console.log('Drag Interaction Started!');
});

L'oggetto DataTransfer

Quando viene inizializzata un'azione di trascinamento l'oggetto DataTransfer viene creato e associato a tale azione. Questo oggetto conserva sia dati che informazioni sull'evento di trascinamento.

  • dropEffect – Il tipo di interazione che il browser deve gestire. I valori possibili sono copy, move, link e none.
  • effectAllowed – I tipi consentiti per l'interazione. I valori possibili sono copy, move, link, copyLink, copyMove, linkMove, all, none e uninitialized (predefinito).
  • files – Una FileList contenente oggetti File, utile se si trascinano file nella finestra del browser.
  • types – Una lista dei formati memorizzati nell'oggetto DataTransfer.
  • setData(format, data) – Imposta un tipo di dati (ad esempio text/html) e il suo valore.
  • getData(format) – Reperisce i dati per il formato specificato.
  • clearData(format) – Elimina i dati per il formato specificato.
  • setDragImage(imgElement, x, y) – Specifica un'immagine come elemento del DOM (non come percorso) da visualizzare durante il trascinamento. Le coordinate indicano la posizione dell'immagine rispetto al puntatore del mouse.

Esempio: trascinamento di file

Partiamo dalla seguente marcatura:


<div id="files">Drop a .txt file here</div> 
<pre id="file-content"></pre>

Scriveremo il seguente codice:


const dropZone = document.getElementById('files');
const fileContainer = document.getElementById('file-content');

dropZone.addEventListener('dragover', e => {
	e.preventDefault();
	e.dataTransfer.dropEffect = 'copy';
}, false);

dropZone.addEventListener('dragenter', e => {
	this.className = 'over';
}, false);

dropZone.addEventListener('dragleave', e => {
	this.className = '';
}, false);

dropZone.addEventListener('drop', e => {
	e.preventDefault();
	this.className = '';
	const fileList = e.dataTransfer.files;
	if (fileList.length > 0) { 
		readTextFile(fileList[0]);
	} 
}, false);

A questo punto utilizziamo le API FileReader per leggere il contenuto del file:


const readTextFile = file => {
	const reader = new FileReader();
	reader.onloadend = e => {
		if (e.target.readyState == FileReader.DONE) {
			const content = reader.result;
			fileContainer.innerHTML = `File: ${file.name} ${content}`; 
		}
	};
	reader.readAsBinaryString(file); 
};

Supporto nei browser

  • IE10+ (con supporto ai file)
  • IE Mobile 10
  • Firefox 3.5+
  • Chrome 4.0+
  • Safari 3.1+
  • Opera 12+

L'autore

Gabriele Romanato, sviluppatore web full stack specializzato in siti, applicativi web ed e-commerce con Node.js e PHP.