Créer un widget Amazon Books avec jQuery et XML

Il est logique de renoncer aux tables de base de données et au code côté serveur lorsque vous devez stocker un nombre limité de données non sensibles. L'accès à ces données peut être un jeu d'enfant avec jQuery car la bibliothèque a été conçue pour parcourir facilement les documents XML. Avec du JavaScript personnalisé et de la magie jQuery, vous pouvez créer des widgets intéressants. Un bon moyen de démontrer cette fonctionnalité consiste à créer un widget de livres Amazon.com pouvant être parcouru..




Préface

Une chose à garder à l'esprit lorsque vous essayez de le faire vous-même est que les paramètres de sécurité d'Internet Explorer ne vous permettent pas de passer des appels XmlHttpRequest à partir du système de fichiers local. Même si vous n'utilisez pas de langage côté serveur, vous devez toujours exécuter le code source à partir d'un serveur Web comme le serveur HTTP d'Apache. Le téléchargement des fichiers sur un compte d'hébergement Web fonctionnerait également.

Ce didacticiel utilise le fichier JavaScript de base jQuery 1.2.6, qui peut être téléchargé ici à partir de Google Code. Aucun autre plugin n'est nécessaire. Voici une capture d'écran du widget dans sa forme finale:

Étape 1: Dissection de l'interface

J'ai créé le graphique suivant avec Illustrator. Il s'agit du cadre pour le widget de livres. Les images découpées finales peuvent être remplacées facilement pour créer des éléments de conception adaptés à vos besoins. L'illustration comprend les boutons suivant et précédent, ainsi que le conteneur des images du livre. Le fichier ZIP source contient un fichier EPS superposé si vous souhaitez effectuer des modifications sans devoir recommencer à zéro..

Une chose que je voulais faire avec ce widget était de m'assurer qu'il était suffisamment flexible pour n'importe quelle taille de colonne. Cela signifiait qu'il fallait non seulement une largeur fluide, mais également accepter des unités de mesure en pixels. Les livres peuvent s'emboîter gracieusement sur plusieurs lignes espacées de manière uniforme, jusqu'à une seule colonne, ou peuvent s'étendre sur une seule ligne aussi large que vous le souhaitez. Cette capture d'écran suivante permet de visualiser comment cela se passera.

Les blocs pleins rose pâle doivent illustrer la grille de découpage d'image. Il y a les deux boutons, ainsi que quatre coins, le fond haut et bas, puis le fond gauche et droit. Les lignes continues rose foncé doivent illustrer les blocs de confinement, qui finiront par former quelques div et une liste non ordonnée. Pour permettre une mise en page fluide, un div interne contiendra l'arrière-plan de gauche et la liste non ordonnée sera imbriquée dans ce div parent, qui contiendra l'arrière-plan de droite..

Étape 2: le HTML

Avant d’arriver au HTML, il est intéressant de noter que je n’utilise pas de fichiers PNG. Vous pourriez très bien substituer les fichiers PNG aux fichiers GIF, sans que cela affecte la fonctionnalité. Cela signifierait toutefois que vous auriez besoin de mettre en œuvre un correctif pour le manque de prise en charge de la transparence PNG dans Internet Explorer. Il existe plusieurs plugins jQuery disponibles.

     Amazon.com Books Widget    
précédent
Suivant

Le HTML n'a rien d'innovant, mais je voudrais souligner quelques points. Le premier concerne la classe "sur dégagée" qui apparaît sur plusieurs éléments. C'est une excellente méthode pour nettoyer les flotteurs sans avoir besoin de balisage supplémentaire. Je discute de cette technique dans un article de blog intitulé Six trucs et astuces CSS indispensables que j'utilise pour chaque projet. En déclarant une largeur et en définissant la propriété de débordement sur masqué sur un div parent, les éléments enfants flottants n'auront plus besoin d'un élément de fin avec la propriété clear.

La deuxième chose que je voudrais souligner est l’élément de la liste des chargeurs. Étant donné que je vais récupérer tous les livres du fichier XML à la fois, le chargeur devrait apparaître immédiatement. J'ai généré un chargeur à partir d'Ajaxload, puis je l'ai centré en arrière-plan. Lorsque le chargement du fichier XML est terminé, je supprime l'élément de liste du DOM et le chargeur disparaît. Voici une capture d'écran de ce à quoi il ressemble avec juste le code HTML et CSS appliqué.

Le widget a une largeur fixe et, pour ce tutoriel, ce sera une seule ligne avec quatre livres affichés à chaque vue. Si aucune largeur n'était appliquée, la largeur de la page ou la largeur du conteneur parent serait alors étendue..

Étape 3: le CSS

Le CSS est assez simple et explicite, je ne passerai donc pas beaucoup de temps à expliquer toutes les facettes de chaque sélecteur. Presque tous les sélecteurs sont des éléments enfants du conteneur parent avec l'identificateur "books". Vous pouvez voir que la largeur appliquée est facultative. Le supprimer permettra au widget de s’étendre et de se contracter librement.

 / * foundation * / body font: normal "Arial", "Helvetica", sans serif;  #books width: 515px; / * facultatif * / #books img border: 0;  #books .clear_both clear: les deux;  #books .float_left, #books ul li float: left; affichage: en ligne;  #books .float_right float: right;  #books .overclear width: 100%; débordement caché;  / * styles * / #books .buttons position: relative; hauteur: 30px; marge: 0 0 5 px 0;  #books .prev position: absolute; en haut: 0; gauche: 0; visibilité: cachée;  #books .next position: absolute; en haut: 0; à droite: 0;  #books .showing margin: 5px 60px 0 60px; text-align: center; taille de police: .8em;  #books .top background: url (… /images/books_top.gif) repeat-x;  #books .inner padding: 0 0 0 20px; marge: 0 0 -20px 0; fond: url (… /images/books_left_mid.gif) repeat-y;  #books ul margin: 0; rembourrage: 0; type de style de liste: aucun; fond: url (… /images/books_right_mid.gif) répéter-y en haut à droite;  #books ul li display: none; position: relative; marge: 0; remplissage: 0 20px 20px 0; taille de police: .8em; z-index: 1;  #books ul li.loader display: block; float: aucun; hauteur: 115px; marge: 0 0 20px -20px; fond: url (… /images/books_loader.gif) no-repeat centre centre;  #books ul li a.info position: absolute; en bas: 20px; à droite: 20px;  #books ul li a.thumb display: block; bordure: 1px solide #ddd;  #books ul li a.thumb img display: block; marge: 0; rembourrage: 3px;  #books .btm background: url (… /images/books_btm.gif) repeat-x;  .books_tool_tip display: none; position: absolue; en haut: 0; gauche: 0; largeur: 350px; z-index: 9999;  .books_tool_tip .books_pointer_left position: absolute; en haut: 0; gauche: 0; largeur: 10px; hauteur: 10px; fond: url (… /images/books_pointer_left.gif);  .books_tool_tip .books_pointer_right position: absolute; en haut: 0; à droite: 0; largeur: 10px; hauteur: 10px; fond: url (… /images/books_pointer_right.gif);  .books_tool_tip .inner border: 1px solid #ddd; remplissage: 15px 15px 3px 15px; marge: 0 0 0 9px; background: #fff;  .books_tool_tip .inner_right margin: 0 9px 0 0;  .books_tool_tip .inner p font-size: .8em; marge: 0; remplissage: 0 0 12px 0; 

Il existe une exception, à savoir l'info-bulle d'information appliquée à un livre lorsque vous survolez l'icône d'information. Chaque info-bulle contient la classe "books_tool_tip" et constitue un élément enfant du corps de la page. Ceux-ci sont positionnés avec JavaScript en fonction de la position de la souris au moment où l'utilisateur déplace le curseur sur l'icône.

Les classes "books_pointer_left" et "books_pointer_right" gèrent les flèches associées à l'info-bulle de détail du livre. L'info-bulle se situe à droite du curseur, mais si elle se trouve en dehors de la fenêtre du navigateur (appelée fenêtre d'affichage), elle se déplacera vers la gauche. Les classes sont permutées et la flèche se déplace également du côté opposé. Cela vous permet de placer le widget dans une disposition de colonne de gauche ou de colonne de droite.

Étape 4: le XML

Ce XML n'a rien de révolutionnaire. Comme vous le verrez, chaque livre contient un titre, un ou des auteurs, une image, une URL Amazon, un total d'avis et une moyenne d'avis. Le XML pourrait être normalisé dans un domaine, c’est le nœud "auteur". Strictement parlant, il peut y avoir plusieurs auteurs et un auteur peut être de deux types, un auteur ou un éditeur. Cependant, je suis resté simple afin de me concentrer sur les fonctionnalités principales. Un bon travail à faire consisterait à voir comment optimiser davantage ce nœud, puis à l'analyser avec succès avec jQuery..

    <![CDATA[Design Patterns: Elements of Reusable Object-Oriented Software]]> Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides      250 4,5    <![CDATA[The Pragmatic Programmer: From Journeyman to Master]]> Andrew Hunt, David Thomas      131 4,5    <![CDATA[Refactoring: Improving the Design of Existing Code]]> Martin Fowler, Kent Beck, John Brant et William Opdyke      139 4,5    <![CDATA[Patterns of Enterprise Application Architecture]]> Martin Fowler      56 4,5    <![CDATA[Head First Design Patterns]]> Elisabeth Freeman, Eric Freeman, Bert Bates et Kathy Sierra      252 4,5    <![CDATA[Introduction to Algorithms]]> Thomas Cormen, Charles Leiserson, Ronald Rivest, Clifford Stein      167 4.0    <![CDATA[The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition)]]> Frederick P. Brooks      128 4,5    <![CDATA[Effective Java (2nd Edition)]]> Joshua Bloch      120 5.0    <![CDATA[Mastering Regular Expressions]]> Jeffrey Friedl      125 4,5    <![CDATA[Introduction to the Theory of Computation, Second Edition]]> Michael Sipser      52 4,5    <![CDATA[Don't Make Me Think: A Common Sense Approach to Web Usability (2nd Edition)]]> Steve Krug      453 4,5    <![CDATA[The Visual Display of Quantitative Information, 2nd edition]]> Edward R. Tufte      96 4,5    <![CDATA[JavaScript: The Definitive Guide]]> David Flanagan      278 4,5    <![CDATA[Designing Interfaces: Patterns for Effective Interaction Design]]> Jenifer Tidwell      47 4,5    <![CDATA[Universal Principles of Design]]> William Lidwell, Kritina Holden et Jill Butler      54 4,5    <![CDATA[Ambient Findability: What We Find Changes Who We Become]]> Peter Morville      46 4.0    <![CDATA[The Search: How Google and Its Rivals Rewrote the Rules of Business and Transformed Our Culture]]> John Battelle      99 4,5    <![CDATA[Beginning PHP and MySQL 5 (2nd Edition)]]> W. Jason Gilmore      100 4.0   

Étape 5: le JavaScript

Le JavaScript est certainement la partie la plus compliquée du tutoriel. Du mieux que je peux, je commence généralement des scripts comme celui-ci en décrivant l'état et le comportement d'un objet pour avoir une idée de la fonctionnalité. Cet objet est simplement appelé "LIVRES". J'utilise également ce qu'on appelle le modèle de module, qui est détaillé par Eric Miraglia sur Yahoo! Blog d'interface utilisateur. Ce modèle de conception vous permet de créer des méthodes et des propriétés privées. Chaque fois que vous relâchez un script dans la nature (comme maintenant), ce modèle aide à éliminer les risques de conflits avec d'autres fonctions et objets que d'autres développeurs utilisent peut-être déjà..

 var LIVRES = fonction () var _P = init: fonction (params) , params: null, données: null, loadXml: function () , première: 0, max: 0, nombre: 0, préchargés: fonction () , browseBooks: fonction (parcourir) , info-bulle: show: fonction (e, $ o) , masquer: fonction (e, $ o) , getMouseCoord: fonction (v, e) , getViewport: function () ; return init: function (params) _P.init (params); ;  ();

Tous mes membres privés que j'ai placés à l'intérieur d'un objet appelé "_P". Cela a plus à voir avec les efforts organisationnels qu'autre chose. Tant qu'un membre ne figure pas dans l'instruction de retour BOOKS, j'aurais très bien pu le créer en tant que variable ou fonction autonome. Comme j'ai besoin d'associer des paramètres publics (paramètres) à des membres privés, j'ai une méthode publique. Cette méthode d’initialisation publique transmet les paramètres à une méthode d’initialisation privée, jouant le rôle d’intermédiaire. Je reviendrai sur ces paramètres dans la dernière étape.

Voici un aperçu du code JavaScript final:

 var LIVRES = fonction () var _P = init: fonction (params) _P.params = params; _P.loadXml (); , params: null, data: null, loadXml: function () $ .ajax (type: "GET", url: _P.params.xmlPath, dataType: "xml", réussite: function (data) _P. data = data; _P.max = _P.params.perView; _P.count = $ ("livre", données) .length; _P.preloadBooks (); _P.browseBooks ();); , premier: 0, max: 0, nombre: 0, préchargés: function () $ ("ul", "#books") .empty (); $ ("livre", _P.data) .each (fonction (i) titre var = = .trim ($ ("titre", cela) .text ()); var href = $ .trim ($ ("href ", this) .text ()); $ (" ul "," #books ") .append (["
  • src ", this) .text ())," ", $ (" image ", this) .attr (" width ")," ", $ (" image ", this) .attr (" height ")," ", titre," "/>
  • "] .join (" ")); $ (" body ") .append (["

    ", titre," (par ", $ .trim ($ (" auteur ", ceci) .text ()),") ","

    average_rating ", this) .text ()),,". gif "/> (", $ .trim ($ ("critiques> total", ceci) .text ()), ")", "

    "] .join (" "));); $ (" .info "," #books ") .hover (fonction (e) _P.tooltip.show (e, $ (" #books_tool_tip_ "+ + ( "a.info", "#books") .index (this)));, fonction (e) _P.tooltip.hide (e, $ ("#books_tool_tip_" + $ ("a.info", " #books ") .index (this)));); $ (" #books .prev ") .click (function () _P.browseBooks (" prev "); renvoyer false;); $ (" # books .next ") .click (function () _P.browseBooks (" next "); return false;);, browseBooks: fonction (browse) if (parcourir ==" prev ") if (_P. first == _P.count && (_P.count% _P.max> 0)) _P.first = _P.first - ((_P.count% _P.max) + _P.max); sinon _P.first = _P.first - (_P.max * 2); var plage = _P.first + _P.max; var start = 1; if (plage> _P.max) start = ((plage - _P.max) + 1); if (_P.first == 0) $ ("#books .prev") .css ("visibilité", "caché"); else $ ("#books .prev") .css ("visibilité", "visible"); if (plage < _P.count ) $( "#books .next" ).css( "visibility", "visible" ); else if ( range >= _P.count) range = _P.count; $ ("#books .next") .css ("visibilité", "caché"); $ ("livre", _P.data) .each (fonction (i) if (i> = _P.first && i < range ) $( "#books li:eq(" + i + ")" ).fadeIn( "slow" ); else $( "#books li:eq(" + i + ")" ).css( "display", "none" ); ); _P.first = range; $( "#books .showing" ).html([ "Viewing ", commencez," - ", gamme," de ", _P.count,""] .join (" "));, info-bulle: show: function (e, $ o) var v = _P.tooltip.getViewport (); var pageX = _P.tooltip.getMouseCoord (v, e) [ 0] + 15; var pageY = _P.tooltip.getMouseCoord (v, e) [1]; $ o.find (".books_pointer_right") .addClass ("books_pointer_left") .removeClass ("books_pointer_right"); if (pageX + $ o.width ()> v.innerWidth + v.pageXOffset) pageX = pageX - $ o.width () - 30; $ o.find (".inner") .addClass ("inner_right"); $ o .find (".books_pointer_left") .addClass ("books_pointer_right") .removeClass ("books_pointer_left"); $ o.css ("left", pageX) .css ("top", pageY) .css ("display") , "bloquer");, masquer: fonction (e, $ o) $ o.css ("display", "none");, getMouseCoord: fonction (v, e) (! e)? e = window.event: e = e; (e.pageX)? v.pageX = e.pageX: v.pageX = e.clientX + v.scrollLeft; (e.pageY)? v.pageY = e.pageY: v. pageY = e.clientY + v.scrollTop; return [e.pageX, e.pageY];, getViewport: function () var viewport = if (self.innerHeight) viewport. pageYOffset = self.pageYOffset; viewport.pageXOffset = self.pageXOffset; viewport.innerHeight = self.innerHeight; viewport.innerWidth = self.innerWidth; else if (document.documentElement && document.documentElement.clientHeight) viewport.pageYOffset = document.documentElement.scrollTop; viewport.pageXOffset = document.documentElement.scrollLeft; viewport.innerHeight = document.documentElement.clientHeight; viewport.innerWidth = document.documentElement.clientWidth; return viewport; ; return init: function (params) _P.init (params); ; ();

    Je ne couvrirai pas toutes les fonctionnalités, mais je voulais souligner quelques aspects très importants du script - le premier étant la méthode "loadXml". C’est l’un des utilitaires AJAX de jQuery et l’une des implémentations AJAX les plus simples à utiliser. Vous pouvez en savoir plus à ce sujet dans la documentation officielle. Après avoir récupéré un fichier XML, de nombreux développeurs effectueront des actions sur les données, toutes dans la partie succès de l'appel. Cela est difficile à résoudre, et je préfère transmettre ces données à d’autres méthodes afin d’agir en conséquence. C'est penser en termes orientés objet, et ça peut être une bonne habitude.

    La méthode "preloadBooks" analyse les données XML et transforme chaque noeud en XHTML pertinent, comprenant à la fois un livre et une info-bulle du livre. L'avantage de jQuery est que les nœuds XML peuvent être traités comme des nœuds HTML. Vous n'avez pas à apprendre deux styles de syntaxe, le seul inconvénient étant que vous devez utiliser la méthode text () de jQuery pour récupérer le contenu entre une balise de début et une balise de fin. Avec HTML, vous utiliseriez la méthode html ().

    Une grande partie du code HTML doit être créée à l'aide de JavaScript. Cela implique souvent une concaténation de chaînes. L'approche traditionnelle consiste à utiliser l'opérateur arithmétique d'addition, mais une approche plus rapide consiste à placer des parties d'une chaîne dans un tableau, puis à les joindre. Je fais cela à plusieurs endroits, et surtout quand ça arrive tout au long d'une boucle, alors c'est le style préféré.

    Maintenant que les livres HTML ont tous été insérés dans le DOM, il est temps d'attacher les événements appropriés pour la navigation. L'action de navigation a lieu dans la méthode "browseBooks". Cette méthode accepte le paramètre "browse", qui prend l'un des deux arguments, "prev" ou "next". Ce n'est pas une action de défilement, mais une transition en fondu. La méthode établira la première position (actuelle), le nombre maximal de livres à parcourir, le nombre de livres restants à parcourir, puis effectuera la transition. Cela aide également à déterminer quand les boutons précédents ou suivants doivent être affichés afin d'empêcher les utilisateurs de naviguer au-delà du nombre de livres répertoriés..

    L'info-bulle implique une petite quantité de JavaScript personnalisé et je voulais décrire deux fonctions: les méthodes "getMouseCoord" et "getViewport". Ce sont des implémentations multi-navigateurs permettant de déterminer la position de la souris en fonction du degré de défilement de la page vers le haut ou le bas ou vers la gauche / la droite. Vous ne devriez jamais avoir à les éditer, et je les ai utilisées avec succès sur plusieurs projets sans aucun problème. La méthode "show" gère également le scénario que j'ai décrit précédemment, lorsque l'info-bulle ne s'affiche pas dans la fenêtre d'affichage calculée..

    Étape 6: le dernier widget

    La dernière chose à faire est de transmettre les paramètres à la méthode d’initialisation JavaScript à partir du code HTML. Il existe trois arguments: le chemin d'accès au fichier XML, le chemin d'accès aux images utilisées dans JavaScript et le nombre de livres à afficher par vue. Pour ce tutoriel, il est supposé qu'il n'y a qu'un seul widget de livres par page (appelé "livres"), c'est pourquoi il n'y a pas de paramètre pour l'ID ou le nom de la classe. Voici le XHTML sous sa forme finale:

         Amazon.com Books Widget       
    précédent
    Suivant

    Profitez de votre widget de livres Amazon.com!

    • Abonnez-vous au flux RSS NETTUTS pour plus de commentaires et d'articles sur le développement Web au quotidien.