190 votes

glisser-déposer des fichiers dans une entrée de fichier html standard

De nos jours, nous pouvons glisser et déposer des fichiers dans un conteneur spécial et les télécharger avec XHR 2. Plusieurs à la fois. Avec des barres de progression en direct, etc. C'est très cool. Exemple ici.

Mais parfois, nous ne voulons pas autant de fraîcheur. Ce que j'aimerais, c'est pouvoir glisser-déposer des fichiers, plusieurs à la fois dans un fichier HTML standard : <input type=file multiple> .

Est-ce possible ? Existe-t-il un moyen de "remplir" l'entrée de fichiers avec les bons noms de fichiers ( ?) à partir du dépôt de fichiers ? (Les chemins de fichiers complets ne sont pas disponibles pour des raisons de sécurité du système de fichiers).

Pourquoi ? Parce que je voudrais soumettre un formulaire normal. Pour tous les navigateurs et tous les appareils. Le glisser-déposer n'est qu'une amélioration progressive visant à améliorer et à simplifier l'interface utilisateur. Le formulaire standard avec entrée de fichier standard (+ multiple ) sera présent. J'aimerais ajouter l'amélioration HTML5.

modifier
Je sais que dans un peu de navigateurs, vous pouvez parfois (presque toujours) déposer des fichiers dans l'entrée de fichier elle-même. Je sais que Chrome fait généralement cela, mais parfois il échoue et charge le fichier dans la page en cours (un gros échec si vous remplissez un formulaire). Je veux le rendre infaillible pour les navigateurs.

2 votes

Préparez-vous à souffrir si vous voulez inclure mac/safari dans vos compatibilités.

1 votes

@Shark8 En fait, Safari/Mac est l'un des rares navigateurs à prendre en charge cette fonctionnalité.

0 votes

En fait, aucun des navigateurs ne le permet. Le champ de saisie du fichier est en lecture seule (pour des raisons de sécurité) et c'est là le problème. Stupide sécurité !

51voto

BjarkeCK Points 1589

J'ai créé une solution pour cela.

$(function () {
    var dropZoneId = "drop-zone";
    var buttonId = "clickHere";
    var mouseOverClass = "mouse-over";

    var dropZone = $("#" + dropZoneId);
    var ooleft = dropZone.offset().left;
    var ooright = dropZone.outerWidth() + ooleft;
    var ootop = dropZone.offset().top;
    var oobottom = dropZone.outerHeight() + ootop;
    var inputFile = dropZone.find("input");
    document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
        e.preventDefault();
        e.stopPropagation();
        dropZone.addClass(mouseOverClass);
        var x = e.pageX;
        var y = e.pageY;

        if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
            inputFile.offset({ top: y - 15, left: x - 100 });
        } else {
            inputFile.offset({ top: -400, left: -400 });
        }

    }, true);

    if (buttonId != "") {
        var clickZone = $("#" + buttonId);

        var oleft = clickZone.offset().left;
        var oright = clickZone.outerWidth() + oleft;
        var otop = clickZone.offset().top;
        var obottom = clickZone.outerHeight() + otop;

        $("#" + buttonId).mousemove(function (e) {
            var x = e.pageX;
            var y = e.pageY;
            if (!(x < oleft || x > oright || y < otop || y > obottom)) {
                inputFile.offset({ top: y - 15, left: x - 160 });
            } else {
                inputFile.offset({ top: -400, left: -400 });
            }
        });
    }

    document.getElementById(dropZoneId).addEventListener("drop", function (e) {
        $("#" + dropZoneId).removeClass(mouseOverClass);
    }, true);

})

#drop-zone {
    /*Sort of important*/
    width: 300px;
    /*Sort of important*/
    height: 200px;
    position:absolute;
    left:50%;
    top:100px;
    margin-left:-150px;
    border: 2px dashed rgba(0,0,0,.3);
    border-radius: 20px;
    font-family: Arial;
    text-align: center;
    position: relative;
    line-height: 180px;
    font-size: 20px;
    color: rgba(0,0,0,.3);
}

    #drop-zone input {
        /*Important*/
        position: absolute;
        /*Important*/
        cursor: pointer;
        left: 0px;
        top: 0px;
        /*Important This is only comment out for demonstration purposes.
        opacity:0; */
    }

    /*Important*/
    #drop-zone.mouse-over {
        border: 2px dashed rgba(0,0,0,.5);
        color: rgba(0,0,0,.5);
    }

/*If you dont want the button*/
#clickHere {
    position: absolute;
    cursor: pointer;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: 20px;
    line-height: 26px;
    color: white;
    font-size: 12px;
    width: 100px;
    height: 26px;
    border-radius: 4px;
    background-color: #3b85c3;

}

    #clickHere:hover {
        background-color: #4499DD;

    }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="drop-zone">
    Drop files here...
    <div id="clickHere">
        or click here..
        <input type="file" name="file" id="file" />
    </div>
</div>

La fonctionnalité de glisser-déposer de cette méthode ne fonctionne qu'avec Chrome, Firefox et Safari. (Je ne sais pas si elle fonctionne avec IE10), mais pour les autres navigateurs, le bouton "Ou cliquez ici" fonctionne bien.

Le champ de saisie suit simplement votre souris lorsque vous faites glisser un fichier sur une zone, et j'ai également ajouté un bouton

Décommentez opacity:0 ; l'entrée du fichier est seulement visible pour que vous puissiez voir ce qui se passe.

0 votes

C'est pourquoi j'ai ajouté un bouton aussi^^ Mais oui, vous avez raison. Je ne l'utiliserais pas non plus... Ou si !

0 votes

J'aimerais bien savoir comment c'est censé fonctionner... il semble que toutes les fonctions de glisser/déposer doivent s'occuper d'ajouter l'effet de survol... mais je n'arrive pas à savoir. Ça a l'air bien dans le bidule, mais je ne pense pas pouvoir l'utiliser car je dois supporter Internet Explorer.

0 votes

@nmz787 vérifiez ce fil de discussion, vous pourriez y trouver une autre solution. stackoverflow.com/questions/1537223/

31voto

Full Decent Points 4453

C'est la façon "DTHML" HTML5 de le faire. Saisie normale du formulaire (qui EST en lecture seule comme l'a souligné Ricardo Tomasi). Ensuite, si un fichier est glissé, il est joint au formulaire. Il faudra modifier la page d'action pour accepter le fichier téléchargé de cette manière.

function readfiles(files) {
  for (var i = 0; i < files.length; i++) {
    document.getElementById('fileDragName').value = files[i].name
    document.getElementById('fileDragSize').value = files[i].size
    document.getElementById('fileDragType').value = files[i].type
    reader = new FileReader();
    reader.onload = function(event) {
      document.getElementById('fileDragData').value = event.target.result;}
    reader.readAsDataURL(files[i]);
  }
}
var holder = document.getElementById('holder');
holder.ondragover = function () { this.className = 'hover'; return false; };
holder.ondragend = function () { this.className = ''; return false; };
holder.ondrop = function (e) {
  this.className = '';
  e.preventDefault();
  readfiles(e.dataTransfer.files);
}

#holder.hover { border: 10px dashed #0c0 !important; }

<form method="post" action="http://example.com/">
  <input type="file"><input id="fileDragName"><input id="fileDragSize"><input id="fileDragType"><input id="fileDragData">
  <div id="holder" style="width:200px; height:200px; border: 10px dashed #ccc"></div>
</form>

C'est encore mieux si vous pouvez faire de toute la fenêtre une zone de dépôt, voir Comment détecter un événement de glisser HTML5 qui entre et sort de la fenêtre, comme le fait Gmail ?

2 votes

Bonne solution mais elle ne fonctionne pas sur IE < 10 car IE 9 et moins ne supporte pas l'API des fichiers HTML5 :(

1 votes

Cette ligne : document.getElementById('fileDragData').value = files[i].slice() ; n'est pas nécessaire, car elle est remplacée par la fonction reader.onload

0 votes

Voici une autre jolie application de glisser-déposer qui n'implique PAS de téléchargement de fichiers. Je mets un lien juste au cas où quelqu'un voudrait en savoir plus. codepen.io/anon/pen/MOPvZK?editors=1010

13voto

Dipak Points 799
//----------App.js---------------------//
$(document).ready(function() {
    var holder = document.getElementById('holder');
    holder.ondragover = function () { this.className = 'hover'; return false; };
    holder.ondrop = function (e) {
      this.className = 'hidden';
      e.preventDefault();
      var file = e.dataTransfer.files[0];
      var reader = new FileReader();
      reader.onload = function (event) {
          document.getElementById('image_droped').className='visible'
          $('#image_droped').attr('src', event.target.result);
      }
      reader.readAsDataURL(file);
    };
});

.holder_default {
    width:500px; 
    height:150px; 
    border: 3px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:150px; 
    border: 3px dashed #0c0 !important; 
}

.hidden {
    visibility: hidden;
}

.visible {
    visibility: visible;
}

<!DOCTYPE html>

<html>
    <head>
        <title> HTML 5 </title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
    </head>
    <body>
      <form method="post" action="http://example.com/">
        <div id="holder" style="" id="holder" class="holder_default">
          <img src="" id="image_droped" width="200" style="border: 3px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>

2 votes

Que montre-t-il à l'utilisateur ? Pouvez-vous faire un violon ou un exemple en ligne ?

1 votes

@Rudie veuillez cliquer sur exécuter le code et glisser-déposer une image pour la visualiser, il affichera l'aperçu de l'image déposée.

6voto

Ricardo Tomasi Points 13398

En théorie, vous pourriez ajouter un élément superposé à l'élément <input/> et utiliser ensuite sa fonction drop pour capturer les fichiers (en utilisant l'API Fichier) et les transmettre à l'entrée files le tableau.

Sauf qu'une entrée de fichier est en lecture seule . Il s'agit d'un vieux problème.

Vous pouvez toutefois contourner complètement le contrôle du formulaire et télécharger via XHR (je ne suis pas sûr de la prise en charge de cette fonction) :

Vous pourriez également utiliser un élément dans la zone environnante pour annuler l'événement de dépôt dans Chrome, et empêcher le comportement par défaut de charger le fichier.

Le dépôt de plusieurs fichiers sur l'entrée fonctionne déjà dans Safari et Firefox.

6 votes

Comme je l'ai dit dans la question : Je connais XHR2 et je ne veux pas l'utiliser. Je suppose que la partie importante : "l'entrée du fichier est en lecture seule". Ça craint... Annuler l'événement de dépôt n'est pas une mauvaise idée ! Pas aussi bonne que je l'avais espéré, mais probablement la meilleure. Le dépôt de plusieurs fichiers fonctionne aussi dans Chrome. Chrome permet maintenant aussi de télécharger des répertoires. Tout cela est très chouette mais n'aide pas mon cas =(

-1voto

Shark8 Points 2227

Ce que vous pourriez faire, c'est afficher une entrée de fichier et la superposer à votre zone de dépôt transparente, en prenant soin d'utiliser un nom tel que file[1] . {Soyez sûr d'avoir le enctype="multipart/form-data" dans votre balise FORM.}

Ensuite, la zone de dépôt gère les fichiers supplémentaires en créant dynamiquement des entrées de fichiers supplémentaires pour les fichiers 2..number_of_files, en veillant à utiliser le même nom de base et en remplissant l'attribut valeur de manière appropriée.

Enfin (front-end) soumettre le formulaire.


Pour gérer cette méthode, il suffit de modifier votre procédure pour gérer un tableau de fichiers.

1 votes

Le fichier d'entrée a un multiple de nos jours. Il n'est pas nécessaire d'avoir plus d'un fichier en entrée. Mais ce n'est pas le problème. Comment puis-je obtenir le File dans l'entrée du fichier ? Je pense que cela nécessite un exemple de code...

1 votes

@Rudie tu ne peux pas, c'est le problème.

1 votes

Ne peut pas quoi ? Plusieurs ? Si, tu peux. Je viens de le dire. Le multiple n'est pas le problème. Le problème, c'est de récupérer les fichiers d'un objet Fichier (glissé) dans un fichier d'entrée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X