Implémentation de HTML5 Drag and Drop

Une des nouvelles fonctionnalités de HTML5 est le glisser-déposer natif. Étonnamment, Internet Explorer prend en charge le glisser-déposer natif depuis la version 5.5; En fait, l'implémentation HTML5 est basée sur le support de IE. Dans le tutoriel d'aujourd'hui, nous verrons comment implémenter un glisser-déposer natif pour créer une interface de panier d'achat simple..


Étape 0. Ce que nous faisons

Voici ce que nous allons construire: c'est un panier d'achat de base avec un panneau de produit et un panneau de chariot. Pour "acheter" un produit, vous pourrez le faire glisser du panneau vers le panier. nous garderons une trace de la quantité et enlèverons les articles du panneau de produits quand ils seront en rupture de stock.

Notez que nous ne construisons pas réellement de panier ici; nous ne travaillerons pas avec les bienfaits côté serveur aujourd'hui. Ceci est juste le front-end; le point est HTML5 glisser-déposer.


Étape 1. Le HTML

Bien sûr, nous allons commencer par le HTML; voici notre coquille:

     Glisser-déposer le panier        

Assez simple: nous lions vers une feuille de style et jQuery; Nous n'utilisons jQuery que pour gérer facilement les événements et les DOM. le glisser-déposer sera natif. Cependant, nous nous heurtons à un mur, car le glisser-déposer HTML5 ajoute quelques propriétés à l'objet événement. JQuery n'utilise pas l'objet événement par défaut. il crée ses propres moyens pour égaliser les problèmes d'objet d'événement. De ce fait, nous n'obtenons pas les propriétés spéciales avec l'objet événement de jQuery. Mais ne t'inquiète pas il y a un plugin pour ça; nous intégrons le glisser-déposer natif pour que tout fonctionne. Enfin, nous allons inclure notre script: dragdrop.js.

Nous sommes maintenant prêts à ajouter à notre liste de produits. Pour les images de produits, j'utilise les icônes de Apple Icon Superpack, créées par SvenVath. (J'ai renommé les icônes avec des noms plus simples et les ai redimensionnées à 180 pixels.)

Ajouter ul # produits comme le premier enfant à l'intérieur du corps. Une fois que cela sera fait, nous examinerons le premier élément de la liste:

 
  • iMac

    Prix: 1199,00 $

    Quantité: dix

  • Nous avons un élément de la liste avec une ancre à l'intérieur; remarquez que chaque article d'ancrage aura une classe de article (important quand on arrive au CSS) et un identifiant personnalisé (important quand on arrive au JavaScript). Ensuite, l'ancre a aussi le draggable = "true" attribut; cela devrait être tout ce dont nous avons besoin pour rendre l'élément déplaçable (nous verrons bientôt quelques mises en garde). Nous utilisons une balise d'ancrage ici afin que vous puissiez faire quelque chose pour les navigateurs sans la prise en charge native du glisser-déposer (bien que nous ne le fassions pas ici). Ensuite, nous avons l'image du produit et une div avec les informations sur le produit. Et oui, il faut emballer le prix et la quantité avec envergure

    Voici le reste des éléments de la liste:

     
  • iPhone

    Prix: 199,00 $

    Quantité: 16

  • Apple TV

    Prix: 299,00 $

    Quantité: 9

  • Écran de cinéma

    Prix: 899,00 $

    Quantité: 4

  • Ipod nano

    Prix: 149,00 $

    Quantité: 20

  • Macbook

    Prix: 1199,00 $

    Quantité: 13

  • Mac Mini

    Prix: 599,00 $

    Quantité: 18

  • Il y a un dernier morceau de HTML: le panier:

     

    Chariot

      Total: $0.00


      Déposer ici pour ajouter au panier

      Et c'est notre HTML!


      Screencast complet



      Étape 2. Le CSS

      Idéalement, tout ce que vous devez faire pour rendre un élément déplaçable est de définir cet attribut sur true. Cependant, il y a plus que cela. Pour que les choses fonctionnent correctement, vous devez définir quelques éléments en CSS. Commençons par penser à ceci: que font les clics et les glissements sur un élément "normal" (indéchiffrable)? Habituellement, il sélectionne du texte. Ensuite, nous voulons nous assurer que nous faisons glisser l'élément, et pas seulement son contenu. Pour traiter avec, besoin d'utiliser le CSS suivant:

       [draggable = true] -moz-user-select: none; -webkit-user-select: aucun; -webkit-user-drag: element; 

      Pour notre commodité, le plug-in de glisser-déposer natif que nous utilisons définit ces propriétés pour nous, afin que nous puissions les laisser de côté si nous le souhaitons. Cependant, nous ferons ceci:

       [glissable = vrai] curseur: déplacer; 

      Commençons le style:

       html hauteur: 100%;  body background: #ececec; marge: 0; rembourrage: 0; police: 13px / 1.5 helvetica, arial, san-serif; hauteur: 100%;  h1, h2 text-align: center;  h2 position: absolute; en bas: 20px; couleur: #fff; texte-ombre: 0 0 10px rgba (0, 0, 0, 0,75); affichage: aucun;  p margin: 0; 

      Puisque nous n'utilisons pas une réinitialisation complète, voici notre pseudo-réinitialisation. Tout devrait être assez explicite. Nous fixons la hauteur à 100% sur le html et corps éléments parce que nous voulons #Chariot être toute la hauteur de l'écran; Pour ce faire, la hauteur de chaque élément parent doit être définie à 100%. Notez également que nous utilisons rgba pour définir la couleur de l'ombre. si un navigateur ne le supporte pas, il n'y aura pas d'ombre sur le h2. Et on cache ça h2 en mettant affichage: aucun. Se souvenir du h2 dit "déposer ici pour ajouter au panier", donc nous allons le faire fondre en premier lorsque le glissement commence et disparaître en fondu quand le glissement se termine.

      Passons à notre liste de produits…

       #products float: left; style de liste: aucun; largeur: 65%; rembourrage: 0;  #products li display: inline; 

      Encore une fois, c'est assez évident. L'important dans cet extrait est que les éléments de la liste seront affichés en ligne. Depuis que nous allons définir bloc de visualisation; float: gauche sur les ancres, IE donnera aux éléments de la liste un effet "d'escalier"; nous pouvons contourner ce bogue en définissant affichage: en ligne sur l'élément parent de l'ancre.

      En parlant des ancres, appelons-les ensuite.

       .item display: block; float: gauche; largeur: 180px; hauteur: 180px; marge: 10px; bordure: solide 1px # 494949; text-align: center; texte-décoration: aucun; couleur: # 000; débordement caché;  .item img border: 0; marge: auto 10px; largeur: 160px; hauteur: 160px;  .item div background: rgb (0, 0, 0); arrière-plan: rgba (0, 0, 0, 0,5); position: relative; en bas: 69px; couleur: # f3f3f3; rembourrage: 5px 0; affichage: aucun; 

      Chaque ancre sera décorée comme une boîte de 180x180px; cela sera rempli avec l'image du produit. L'information produit div sera positionnée sur l'image, en bas du carré. Notez que nous devons définir une couleur d'arrière-plan, puis la réinitialiser pour les navigateurs modernes, car IE ne prend pas en charge le format RGBa. Nous mettons affichage: aucun sur cette info div afin que nous puissions le faire disparaître quand le "client" survole et éteint, respectivement.

      Il ne reste plus qu'à styler le panier d'achat; nous y jetterons un coup d'oeil, mais souvenez-vous que les éléments de la liste seront insérés par jQuery plus tard, vous ne verrez donc pas cela se produire pour l'instant..

       #cart float: right; couleur de fond: #ccc; largeur: 25%; rembourrage: 0 5%; hauteur: 100%;  #cart ul padding: 0;  #cart li list-style: none; border-bottom: 1px solide # 494949; rembourrage: 5px;  #cart .quantity font-weight: bold; padding-right: 10px; marge droite: 10px; border-right: solide 1px # 494949; affichage: inline-block; largeur: 15px; text-align: right;  #cart .price float: right;  #total float: right; 

      Éléments avec les classes quantité et prix sera dans la liste des éléments insérés dynamiquement.

      Voilà pour CSS. avant de passer à la vedette de ce spectacle, regardons notre travail jusqu'à présent.



      Étape 3. Le JavaScript

      Nous l'avons fait au JavaScript; selon le médecin HTML5:

      HTML 5 DnD est basé sur l'implémentation originale de Microsoft, qui était disponible dès Internet Explorer 5! Actuellement pris en charge dans IE, Firefox 3.5 et Safari 4.

      Voici une liste des événements que HTML5 propose par glisser-déposer:

      • traîne
      • dragstart
      • trainer
      • dragenter
      • glisser
      • dragend
      • laissez tomber

      Nous n'utiliserons pas tout cela, mais nous verrons comment ils fonctionnent la plupart d'entre eux.

      Tout d'abord, nous allons travailler avec nos produits:

       $ ('. item') .bind ('dragstart', function (evt) evt.dataTransfer.setData ('text', this.id); $ ('h2'). fadeIn ('fast');) .hover (function () $ ('div', this) .fadeIn ();, function () $ ('div', this) .fadeOut (););

      Nous commençons par saisir tous les objets; ensuite, nous lions un funciton à la dragstart un événement; cet événement se déclenchera lorsque nous commencerons à faire glisser l'événement. La première chose à faire lorsqu'un objet est déplacé est de définir des données. En fait, si aucune donnée n'est définie, Firefox ne laissera pas l'élément glisser. Le fait de faire glisser des événements est une propriété d'objet appelée objet transfert de données; nous allons utiliser deux méthodes de cette propriété: setData et getData. Ici, nous utilisons le setData méthode, qui prend deux paramètres: un format de données et les données. Nous utiliserons le type de données 'text'. Ensuite, nous allons définir les données comme étant l'id de l'élément que l'utilisateur fait glisser. Ensuite, nous allons fondre dans le h2 comme une invite au client.

      Nous utilisons également la méthode jQuery hover pour afficher en fondu l’information sur le produit lorsque nous le survolons et le masquer en fondu. Notez que nous transmettons le nœud sur lequel nous survolons en tant que contexte afin que nous n'obtenions que la div du produit approprié..

      Ajoutons maintenant les gestionnaires d’événements à la #Chariot. Nous allons agir sur le trainer, dragenter, et laissez tomber événements:

       $ ('# cart') .bind ('dragover', fonction (evt) evt.preventDefault ();) .bind ('dragenter', fonction (evt) evt.preventDefault ();) .bind ( 'drop', function (evt) );

      Pour que l'événement drop se déclenche, nous devons annuler l'action par défaut sur le trainer un événement; cet événement se déclenche de manière continue sur la cible de dépôt lorsqu'un élément déplaçable est déplacé dessus. Pour IE uniquement, nous devons annuler l'action par défaut sur le dragenter événement, qui se produit uniquement lorsque l'élément déplaçable entre dans la cible de dépôt. Les raisons de l'annulation de l'action par défaut sont un peu floues; pour être honnête, je ne les comprends pas vraiment. Voici ce que Remy Sharp en dit:

      Ce qu’il indique au navigateur, c’est que cet élément est celui contre lequel nous voulons attraper l’événement de glisser, sinon le navigateur poursuit son action normale. Donc, en annulant l'événement, il indique au navigateur que c'est l'élément qui doit commencer à se déplacer.

      Je dois noter que jQuery nous aide un peu ici; normalement, nous devrions aussi retourne faux ça marche dans IE; cependant, jQuery est corrigé preventDefault fait ça pour nous.

      Maintenant le laissez tomber un événement; cet événement est également déclenché sur la cible de largage, qui est div # cart dans notre cas. Avant de regarder la fonction, parlons de ce que cette fonction est supposée faire:

      • obtenir le produit que nous avons abandonné
      • si le produit a déjà été acheté, ajoutez-en un à la quantité achetée; sinon, ajoutez l'article au panier
      • décrémenter la quantité de produit
      • mettre à jour le prix total

      Voici la première partie:

       var id = evt.dataTransfer.getData ('text'), item = $ ('#' + id), cartList = $ ("# cart ul"), total = $ ("# total span"), price = $ ('p: eq (1) span', item) .text (), prevCartItem = null, notInCart = (fonction () var lis = $ ('li', cartList), len = lis.length, i; for (i = 0; i < len; i++ )  var temp = $(lis[i]); if (temp.data("id") === id)  prevCartItem = temp; return false;   return true;  ()), quantLeftEl, quantBoughtEl, quantLeft;

      Je connais; il y a beaucoup de variables, mais nous les utiliserons toutes. Allons sur eux; d'abord, nous obtenons les données textuelles que nous avons transférées avec l'événement; nous avons transféré l'identifiant de cette manière car il n'y a rien dans l'objet event qui nous indique quel élément a été déposé sur notre cible; nous allons obtenir l'id puis l'utiliser pour trouver l'élément qui a été supprimé. Ensuite, nous obtenons la liste des paniers et la fourchette de prix totale. Ensuite, nous aurons le prix de l'article individuel; nous savons qu'il s'agit de l'étendue dans le deuxième paragraphe de l'élément, nous pouvons donc utiliser l'élément comme paramètre de contexte. Nous allons mettre prevCartItem à null pour le moment, mais nous l'utilisons pour voir si l'élément glissé dans le panier est déjà là. La valeur de notIncart est une fonction anonyme invocante; il va parcourir chaque élément de la cartList (encore une fois, nous utilisons le paramètre context) et vérifiera si la propriété data identifiant est la même que la variable identifiant. Pour comprendre cela, vous devez savoir que lorsque nous ajouterons des éléments de liste au panier, nous utiliserons jQuery. Les données méthode pour définir l'ID de produit de magasin avec l'élément. Dans cette fonction, nous recherchons un élément de la liste avec les bonnes données; si nous en trouvons un, l’article est déjà dans le panier et nous mettons donc notIncart à faux; si ce n'est pas dans le panier, nous allons définir la variable sur true. Enfin, nous allons utiliser quantLeftEl, quantBoughtEl, et quantLeft lors de la mise à jour des quantités.

      Maintenant, pour l'action:

       $ ("h2"). fadeOut ('fast'); if (notInCart) prevCartItem = $ ('
    • ', text: $ (' p: premier ', item) .text (), data: id: id). prepend ($ ('', ' classe ':' quantité ', texte:' 0 ')). prepend ($ ('', ' class ':' price ', text: price)). appendTo (cartList);
    • Tout d'abord, nous allons effacer le h2 rapide. Ensuite, si l'article ne se trouve pas dans le panier, nous l'ajouterons au panier. Pour ce faire, nous allons créer un élément de liste. ensuite, nous pouvons passer un littéral d'objet en tant que second paramètre pour définir les propriétés de notre nouvel élément de liste. Nous allons définir le texte sur le nom du produit; cela vient du premier paragraphe du produit. Ensuite, nous définissons les données dont nous avons parlé ci-dessus.

      Ensuite, nous ajouterons une extension à cet élément de la liste. nous allons lui donner une classe de 'quantité' (n'oubliez pas de mettre la classe entre guillemets, car c'est un mot réservé) et mettre le texte à zéro; oui, je sais que cela devrait en être un, car ils viennent de mettre l'article dans le panier, mais nous l'incrémenterons plus tard… et vous verrez pourquoi.

      Nous ajouterons une autre durée à l'élément de la liste, cette fois pour le prix. Nous allons faire flotter le prix à droite, donc il semblerait logique de ajouter il; mais cela causerait un bug float dans IE; l'envergure flotterait réellement à droite et en dessous de l'élément de la liste.

      Enfin, nous allons ajouter l'élément de la liste à la liste du panier..

      La dernière partie de cette fonction sera exécutée, que l'article soit déjà dans le panier ou non:

       quantLeftEl = $ ('p: last span', item); quantLeft = parseInt (quantLeftEl.text (), 10) - 1; quantLeftEl.text (quantLeft); quantBoughtEl = $ ('. quantité', prevCartItem); quantBoughtEl.text (parseInt (quantBoughtEl.text (), 10) + 1); if (quantLeft === 0) item.fadeOut ('fast'). remove ();  total.text ((parseFloat (total.text (), 10) + parseFloat (price.split ('$') [1])). toFixed (2)); evt.stopPropagation (); retourne faux;

      Nous allons d'abord obtenir la quantité de l'article du produit; Il s'agit de la quantité restante lorsque le client a traîné l'article dans le panier. nous aurons alors la quantité qui reste vraiment; mais c'est une chaîne, nous utilisons donc la fonction native analyse pour le convertir en nombre (utilisez 10 comme base pour vous assurer que nous obtenons un nombre décimal) et en soustraire un. Ensuite, nous réinitialisons la quantité, en utilisant jQuery texte méthode.

      Ensuite, nous obtenons la quantité achetée par l'utilisateur. c'est l'élément avec une classe de «quantité»; nous utilisons le prevCartItem en tant que contexte; cela fonctionne parce que si l'article était déjà dans le panier, prevCartItem a été défini dans cette fonction anonyme; s'il n'était pas dans le panier, nous le configurions lorsque nous avons créé l'entrée de panier. Nous pouvons ensuite définir la valeur du texte en obtenant la valeur actuelle, en convertissant en un nombre et en en ajoutant un..

      Que se passe-t-il lorsque la quantité restante atteint zéro? S'il est égal à zéro, nous allons effacer l'élément et le supprimer..

      Enfin, nous devons mettre à jour le prix total. Nous avons la durée totale, nous pouvons donc simplement réinitialiser le texte; ce que nous faisons est d'obtenir le texte actuel, en le convertissant en nombre (cette fois, nous utilisons parseFloat garder les cents), diviser le dollar en déduisant le prix et le convertir en nombre puis en ajoutant deux valeurs. Enfin, nous allons utiliser toFixed pour vous assurer que nous montrons toujours la valeur correcte en cents.

      Enfin, nous ne voulons pas la laissez tomber drop événement à bulle, donc nous allons arrêter sa propagation et renvoyer false;


      Étape 4. Le projet terminé

      Bon travail, nous avons fini; voici un coup de notre panier en action:


      Si vous voulez vérifier ce que font les autres événements de glisser-déposer, ajoutez ceci au script:

       $ ('# cart'). bind ('dragleave', fonction (evt) console.log ('dragleave');); $ ('. item') .bind ('dragend', fonction (evt) console.log ('dragend');) .bind ('dragstart', fonction (evt) console.log ('dragstart') ;) .bind ('drag', function (evt) console.log ('drag'););

      Même si le glisser-déposer HTML5 natif n'est peut-être pas encore tout à fait prêt pour le prime time (Opera ne le prend pas en charge), il est vraiment excitant de voir où vont les choses.!