post_ico4

Przeciąganie plików, czyli wczytywanie za pomocą metody drag&drop

Wczytywanie różnego rodzaju plików (zdjęć, dokumentów PDF itp) jest podstawową funkcją niemal każdego serwisu (niezależnie czy chodzi o backend, czy frontend). Jeszcze niedawno operacja ta była dostępna tylko za pomocą znacznika <input type=”file” /> (pomijam wykorzystanie Flasha i Javy), ale taki sposób nie był nigdy ani wygodny, ani estetyczny. Na szczęście, wraz z nadejściem HTML5 mamy takie zdarzenia JS jak drop i dragover.

Dzięki tym zdarzeniom oraz obiektowi XMLHttpRequest możemy przeciągać i wysyłać pliki tak łatwo jak w aplikacjach deskopowych. Spójrzmy na kod.

<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" ></script>
        <style>
            body{
                font-size: 12px;
                font-family: Arial;
                color: #000000;
            }
            #drop_zone{
                padding: 20px;
                width:150px;
                border: 1px dashed #000000;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <form method="post" action="upload.php" enctype="multipart/form-data">
            <div id="drop_zone">Przeciągnij tutaj plik</div>
            <output id="list"><ul></ul></output>
        </form>
        <script type="text/javascript">
            function handleFileSelect(evt) {
                xhr = new XMLHttpRequest();
                evt.stopPropagation();
                evt.preventDefault();

                var files = evt.dataTransfer.files; // FileList object.

                // files is a FileList of File objects. List some properties.
                var output = '';
                f = files[0];
                output += '<li><strong>' + escape(f.name) + '</strong> (' + f.type + ') - ';
                output += f.size + ' bytes, last modified: ';
                output += '<span class="info"></span></li>';
                $("#list ul").append(output);
                xhr.open("post", "upload.php", true);
                xhr.upload.onprogress = function(e) {
                    if (e.lengthComputable) {
                        var percentComplete = (e.loaded / e.total) * 100;
                        console.log(percentComplete + '% uploaded');
                        $("#list li:last .info").html("Wgrywanie..." + parseInt(percentComplete) + " %");
                        $("#drop_zone").html("Proszę czekać...");
                    }
                };
                xhr.onload = function() {
                    // do something to response
                    console.log(this.responseText);
                    $("#list li:last").css("color", "#008416");
                    $("#list li:last .info").html("Wczytano plik!");

                    $("#drop_zone").html("Przeciągnij tutaj plik");
                };
                var formData = new FormData();
                formData.append('file', f);
                xhr.send(formData);
            }

            function handleDragOver(evt) {
                evt.stopPropagation();
                evt.preventDefault();
                evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
            }

            // Setup the dnd listeners.
            var dropZone = document.getElementById('drop_zone');
            dropZone.addEventListener('dragover', handleDragOver, false);
            dropZone.addEventListener('drop', handleFileSelect, false);
        </script>
    </body>
</html>

W funkcji handleFileSelect() za pomocą evt.dataTransfer.files pobieramy tablicę przeciągniętych plików. Następnie, za pomocą XMLHttpRequest przesyłamy plik na serwer. Dodatkowo dodałem komunikaty dla użytkownika informujące o „postępach” wysyłania plików.

Działanie skryptu możecie zobaczyć na tej stronie. Zachęcam do podejrzenia konsoli w Fireburgu :).

Co sądzisz o wpisie?
BeżnadziejnySłabyŚredniDobryBardzo dobry (Brak ocen, bądź pierwszy!)
Loading...
  • czubeka2

    Super! Od dawna szukałem rozwiązania tego problemu. Wszystko fajnie i w łatwy sposób wytłumaczone. Dzięki!

  • outlands

    Wygląda i działa nieźle. Przydałby się do tego osobny wpis, rozszerzający możliwość formularza o:
    + uwzlędnianie określonych typów pliku, rozszerzenia i max. wielkości
    + usuwanie polskich znaków z nazwy
    + opcję blokowania pola po wysłaniu 1 pliku lub nadpisywania go, jesli chcemy mieć możlwość przesłania tylko jednego pliku
    + informację, jak zapisać informację z jquery do np. pól hidden w formularzu lub sesji, by po przesłaniu całego formularza móc np. zapisać info o pliku do bazy.

    Pozdrawiam, świetna i przydatna strona.

    • W sumie można by napisać taki kompletny skrypt do uploadu z zapisem do bazy danych itp. Zastanowię się w najbliższym czasie jak to rozwiązać.