Dans ce tutoriel, nous allons renforcer nos compétences en API Web History. Nous allons créer un motif UX sur le Web qui est aimé et détesté dans la même mesure: défilé interminable.
Le défilement infini est un modèle d'interface qui charge un nouveau contenu lorsque nous atteignons la fin d'une page Web donnée. On peut soutenir que le défilement infini peut conserver l’engagement des utilisateurs lorsqu’il est mis en œuvre judicieusement; certains des meilleurs exemples sont sur les plateformes sociales comme Facebook, Twitter et Pinterest.
Il est à noter, cependant, que nous prenons une place importante par rapport à ce que nous avions construit dans notre précédent tutoriel, Lovely, Smooth Page Transitions With the History Web API. Dans ce didacticiel, nous aborderons les interactions de défilement des utilisateurs, qui peuvent se produire très fréquemment. Si nous ne faisons pas attention à notre code, cela aura un impact négatif sur les performances de notre site Web. Assurez-vous de lire les tutoriels précédents avant d'essayer celui-ci, juste pour vous donner une bonne compréhension de ce que nous faisons..
Néanmoins, si vous êtes enthousiasmé par l’idée d’un défi, attachez votre ceinture de sécurité, préparez-vous et commençons!
Notre site est un blog statique. Vous pouvez le construire à partir de HTML brut ou utiliser un générateur de site statique tel que Jekyll, Middleman ou Hexo. Notre démo pour ce tutoriel se présente comme suit:
Plaine vieux blanc.Il y a plusieurs choses concernant la structure HTML qui nécessitent votre attention.
- Comme vous pouvez le constater à partir de l'extrait de code ci-dessus, l'article doit être intégré à un élément HTML avec un ID unique. Vous pouvez utiliser un
div
ou unsection
élément, sans contrainte en terme de nommer leidentifiant
pour l'élément.- En outre, sur l’article lui-même, vous devrez ajouter un
data-article-id
attribut qui contient le correspondantidentifiant
numéro de l'article.N'hésitez pas à élaborer en termes de styles de site Web; le rendre plus coloré, engageant ou ajouter plus de contenu.
Charger le JavaScript
Pour commencer, chargez les bibliothèques JavaScript suivantes dans l’ordre suivant sur chaque page de votre blog.
- jquery.js: la bibliothèque que nous allons utiliser pour sélectionner des éléments, ajouter un nouveau contenu, ajouter une nouvelle classe et exécuter des requêtes AJAX.
- histoire.js: une polyfill qui cale l’API d’histoire native des navigateurs.
Notre plugin jQuery personnalisé
En plus de ces deux éléments, nous devrons charger notre propre fichier JavaScript dans lequel nous pourrons écrire les scripts à exécuter. défilé interminable. L'approche que nous allons adopter consiste à envelopper notre code JavaScript dans un plugin jQuery, plutôt que de l'écrire directement comme nous l'avons fait dans les tutoriels précédents.
Nous allons commencer le plugin avec jQuery Plugin Boilerplate. Cela ressemble au Boilerplate HTML5 dans la mesure où il fournit une collection de modèles, de modèles et de bonnes pratiques sur lesquels construire un plugin jQuery..
Téléchargez la Boilerplate, placez-la dans le répertoire de votre site Web où se trouvent tous les fichiers JavaScript (tels que
/ assets / js /
) et renommez le fichier en «keepcrolling.jquery.js» (ce nom a été inspiré par Dory de Finding Nemo et sa célèbre ligne «Keep Swimming»).assets / js ├── Keepcrolling.jquery.js Keepcrolling.jquery.js.map └── SRC └── Keepcrolling.jquery.jsLe plugin nous permettra d’introduire de la flexibilité avec Les options ou Réglages.
Observer la structure du plugin jQuery
Écrire un plugin jQuery nécessite une façon de penser légèrement différente, nous allons donc d'abord examiner la structure de notre plugin jQuery avant d'ajouter du code. Comme vous pouvez le voir ci-dessous, j'ai divisé le code en quatre sections:
; (function ($, window, document, undefined) "use strict"; // 1. var pluginName = "keepScrolling", default = ; // 2. plugin de la fonction (element, options) this.element = element; this.settings = $ .extend (, paramètres par défaut, options); this._defaults = paramètres par défaut; this._name = pluginName; this.init (); // 3. $ .extend (Plugin.prototype, init: function () console.log ("Plugin initialisé");,); // 4. $ .fn [pluginName] = fonction (options) renvoie this.each (fonction () if (! $ .data (this, "plugin_" + pluginName)) $ .data (this, "plugin_" + pluginName, new Plugin (this, options));) (jQuery, window, document);
- Dans la première section du code, nous spécifions le nom de notre plugin,
poursuivre le défilement
, avec «cas de chameau» selon les conventions de nommage communes à JavaScript. Nous avons aussi une variable,défauts
, qui contiendra les paramètres par défaut du plugin.- Ensuite, nous avons la fonction principale du plugin,
Brancher()
. Cette fonction peut être comparée à un "constructeur" qui, dans ce cas, initialise le plugin et fusionne les paramètres par défaut avec ceux passés lors de l'instanciation du plugin..- La troisième section est où nous allons composer nos propres fonctions pour servir la fonctionnalité de défilement infini.
- Enfin, la quatrième section est une section qui englobe le tout dans un plugin jQuery.
Avec tout cela, nous pouvons maintenant composer notre code JavaScript. Et nous commençons par définir les options par défaut de notre plugin.
Les options
; (function ($, window, document, undefined) "use strict"; var pluginName = "keepScrolling", default = floor: null, article: null, data: ;…) (jQuery, window, document);Comme vous pouvez le voir ci-dessus, nous avons défini trois options:
sol
: un sélecteur d'identifiant, tel que#sol
ou#bas de page
-que nous considérons la fin du site ou le contenu. En règle générale, ce serait le pied de page du site.article
: un sélecteur de classe qui enveloppe l'article.Les données
: comme nous n'avons accès à aucune API externe (notre site Web est statique), nous devons transmettre une collection de données d'article telles que l'URL, l'ID et le titre de l'article au format JSON comme argument d'option..Les fonctions
Ici nous avons le
init ()
. Dans cette fonction, nous ajouterons un certain nombre de fonctions qui doivent être exécutées immédiatement lors de l'initialisation du site. Par exemple, nous sélectionnons le sol du site.$ .extend (Plugin.prototype, // La fonction 'init ()'. init: function () this.siteFloor = $ (this.settings.floor); // sélectionne l’élément défini comme étage du site. ,);Il y a aussi quelques fonctions que nous allons exécuter à l'extérieur l'initialisation. Nous ajoutons ces fonctions pour les créer et les ajoutons après la
init
une fonction.Le premier ensemble de fonctions que nous allons écrire est celui que nous utilisons pour récupérer ou retourner une «chose»; tout élément d'une chaîne, d'un objet ou d'un nombre qui sera réutilisable dans les autres fonctions du plug-in. Ceux-ci incluent des choses à:
Obtenez tous les articles sur la page:
/ ** * Recherche et renvoie la liste des articles de la page. * @return jQuery Object Liste des articles sélectionnés. * / getArticles: function () return $ (this.element) .find (this.settings.article); ,Obtenez l'adresse de l'article. Dans WordPress, cela est communément appelé le "post slug".
/ ** * Retourne l'adresse de l'article. * @param Integer i L'index de l'article. * @return String L'adresse de l'article, par exemple. 'post-two.html' * / getArticleAddr: function (i) var href = window.location.href; var root = href.substr (0, href.lastIndexOf ("/")); return root + "/" + this.settings.data [i] .address + ".html"; ,Obtenir l'identifiant et l'adresse du prochain article à récupérer.
/ ** * Retourne le "prochain" article. * @return Object Les 'id' et 'url' du prochain article. * / getNextArticle: function () // Sélectionnez le dernier article. var $ last = this.getArticles (). last (); var articlePrevURL; / ** * Il s'agit d'une méthode simplifiée pour déterminer l'ID de contenu. * * Nous soustrayons ici le dernier identifiant de poste par «1». * Idéalement, nous devrions appeler un point de terminaison API, par exemple: * https://www.techinasia.com/wp-json/techinasia/2.0/posts/329951/previous/ * / var articleID = $ last.data ( "article-id"); var articlePrevID = parseInt (articleID, 10) - 1; // Previous ID // Boucle dans l'option 'data' et obtient l'adresse correspondante. pour (var i = this.settings.data.length - 1; i> = 0; i--) if (this.settings.data [i] .id === articlePrevID) articlePrevURL = this.getArticleAddr (i ) return id: articlePrevID, url: articlePrevURL; ,Voici les fonctions d’utilité du plugin; une fonction qui est responsable de faire une "chose" particulière. Ceux-ci inclus:
Une fonction qui indique si un élément entre dans la fenêtre. Nous l'utilisons principalement pour dire si le site défini «sol» est visible dans la fenêtre.
/ ** * Détecte si l'élément cible est visible. * http://stackoverflow.com/q/123999/ * * @return Boolean 'true' si l'élément dans la fenêtre d'affichage et 'false' dans le cas contraire. * / isVisible: function () if (instance de jQuery cible) target = target [0]; var rect = target.getBoundingClientRect (); return rect.bottom> 0 && rect.right> 0 && rect.left < ( window.innerWidth || document.documentElement.clientWidth ) && rect.top < ( window.innerHeight || document.documentElement.clientHeight ); ,Une fonction qui arrête l'exécution d'une fonction. connu comme rebondir. Comme mentionné précédemment, nous allons traiter des activités de défilement des utilisateurs qui se déroulent à un rythme très fréquent. Ainsi, une fonction dans le
faire défiler
L'événement sera exécuté fréquemment, après le défilement de l'utilisateur, ce qui rendra l'expérience du défilement sur le site lente ou lente..La fonction anti-rebond ci-dessus réduira la fréquence d'exécution. Il attendra le temps spécifié, à travers le
attendre
paramètre, après que l'utilisateur arrête de faire défiler avant d'exécuter la fonction./ ** * Retourne une fonction qui, tant qu'elle continue à être invoquée, ne sera pas déclenchée. * La fonction sera appelée après avoir cessé d'appeler pendant N millisecondes. * Si immédiat est passé, déclenchez la fonction sur le bord d'attaque, au lieu de * la fin. * * @link https://davidwalsh.name/function-debounce * @link http://underscorejs.org/docs/underscore.html#section-83 * * @param Fonction func Fonction pour annuler * @param Integer wait Temps en ms avant l'exécution de la fonction * @param Boolean immédiat * @return Void * / isDebounce: function (func, wait, immédiat) var timeout; return function () var contexte = this, args = arguments; var later = function () timeout = null; if (! immediate) func.apply (context, args); ; var callNow = immédiat &&! timeout; clearTimeout (délai d'attente); timeout = setTimeout (plus tard, attendez); if (callNow) func.apply (context, args); ; ,Une fonction qui détermine s'il faut continuer ou abandonner une opération.
/ ** * Procède ou non à l'extraction d'un nouvel article. * @return Boolean [description] * / isProceed: function () if (articleFetching // vérifie si nous recherchons actuellement un nouveau contenu. || articleEnding // vérifie s'il n'y a plus d'article à charger. ||! this. isVisible (this.siteFloor) // vérifie si le "sol" défini est visible.) return; if (this.getNextArticle (). id <= 0 ) articleEnding = true; return; return true; ,Nous allons utiliser la fonction utilitaire précédente,
isProceed ()
, examiner si toutes les conditions sont réunies pour continuer à extraire du nouveau contenu. Si tel est le cas, la fonction qui suit s’exécutera, récupérant le nouveau contenu et l’ajoutant après le dernier article../ ** * Fonction pour récupérer et ajouter un nouvel article. * @retour vide * / fetch: function () // Doit continuer ou pas? if (! this.isProceed ()) return; var main = this.element; var $ articleLast = this.getArticles (). last (); $ .ajax (url: this.getNextArticle (). url, type: "GET", dataType: "html", beforeSend: function () articleFetching = true;) / ** * lorsque la demande est complète et il réussit * à récupérer le contenu, nous ajoutons le contenu. * / .done (function (res) $ articleLast .after (function () if (! res) return; return $ (res) .find ("#" + main.id) .html (); );) / ** * Lorsque la fonction est terminée, qu'elle "échoue" ou "soit terminée", * définit toujours le "articleFetching" sur false. * Il spécifie que nous avons terminé la récupération du nouveau contenu. * / .always (function () articleFetching = false;); ,Ajouter cette fonction dans le
init
. Donc, la fonction sera exécutée dès que le plugin est initialisé, puis récupère le nouveau contenu lorsque les conditions sont remplies.init: function () this.siteFloor = $ (this.settings.floor); // sélectionne l'élément défini comme étage du site. this.fetch (); ,Ensuite, nous allons ajouter une fonction pour modifier l'historique du navigateur avec l'historique API Web. Cette fonction particulière est un peu plus complexe que nos fonctions précédentes. La partie la plus délicate ici est de savoir quand exactement nous devrions changer l’historique lors du défilement de l’utilisateur, du titre du document, ainsi que de l’URL. Voici une illustration pour simplifier l'idée de la fonction:
Comme vous pouvez le voir sur la figure, nous avons trois lignes: «ligne de toit», «ligne médiane» et «ligne de plancher» illustrant la position de l'article dans la fenêtre d'affichage. L'image montre que le bas du premier article, ainsi que le haut du deuxième article, est maintenant au milieu. Cela ne précise pas l'intention de l'utilisateur quant à l'article qu'il regarde; est-ce le premier message ou est-ce le deuxième message? Par conséquent, nous ne changerions pas l'historique du navigateur lorsque deux articles se trouvent à cette position..
Nous enregistrerons l'historique dans le post suivant lorsque le haut de l'article atteindra la «ligne du toit», car il occupe la majeure partie de la partie visible de la fenêtre..
Nous enregistrons l'historique du message précédent lorsque son fond touche la «ligne du sol», de la même manière, puisqu'il occupe maintenant la majeure partie de la partie visible de la fenêtre d'affichage..
C’est le code «tant que» que vous devrez ajouter:
init: function () this.roofLine = Math.ceil (window.innerHeight * 0.4); // set the roofLine; this.siteFloor = $ (this.settings.floor); this.fetch (); , / ** * Modifier l'historique du navigateur. * @retour vide * / history: function () if (! window.History.enabled) return; this.getArticles () .each (fonction (index, article) var scrollTop = $ (fenêtre) .scrollTop (); var articleOffset = Math.floor (article.offsetTop - scrollTop); if (articleOffset> this.threshold) return; var articleFloor = (article.clientHeight - (this.threshold * 1.4)); articleFloor = Math.floor (articleFloor * -1); if (articleOffset < articleFloor ) return; var articleID = $( article ).data( "article-id" ); articleID = parseInt( articleID, 10 ); var articleIndex; for ( var i = this.settings.data.length - 1; i >= 0; i--) if (this.settings.data [i] .id === articleID) articleIndex = i; var articleURL = this.getArticleAddr (articleIndex); if (window.location.href! == articleURL) var articleTitle = this.settings.data [articleIndex] .title; window.History.pushState (null, articleTitle, articleURL); .bind (this)); ,Enfin, nous créons une fonction qui exécutera le
chercher ()
et lel'histoire()
lorsque l'utilisateur fait défiler la page. Pour ce faire, nous créons une nouvelle fonction appeléescroller ()
, et lancez-le à l'initialisation du plugin./ ** * Fonctions à exécuter pendant le défilement. * @return Void * / scroller: function () window.addEventListener ("scroll", this.isDebounce (function () this.fetch (); this.history ();, 300) .bind (this ), faux );Et comme vous pouvez le voir ci-dessus, nous rebondir ceux-ci comme à la fois effectuer AJAX et changer l'historique du navigateur sont une opération coûteuse.
Ajout d'un espace réservé de contenu
Ceci est facultatif, mais recommandé afin de respecter l'expérience de l'utilisateur. L'espace réservé fournit un retour d'information à l'utilisateur, signalant qu'un nouvel article est en cours de création..
Tout d'abord, nous créons le modèle d'espace réservé. Généralement, ce type de modèle est placé après le pied de page du site..
N'oubliez pas que l'article de substitution, sa structure, doit ressembler au contenu réel de votre blog. Ajustez la structure HTML en conséquence.
Les styles d'espace réservé sont plus simples. Il comprend tous les styles de base à mettre en page comme l'article réel, l'animation
@ keyframe
qui simule le sens de chargement et le style de basculement de la visibilité (l’espace réservé est initialement masqué; il n’est affiché que lorsque l’élément parent a lealler chercher
classe)..espace réservé couleur: @ grey-light; rembourrage en haut: 60px; rembourrage en bas: 60px; border-top: 6px solid @ grey-briquet; affichage: aucun; .fetching & display: block; p display: block; hauteur: 20px; arrière plan: gris clair; & __ header animation-delay: .1s; h1 hauteur: 30px; couleur de fond: @ grey-light; & __ p-1 animation-delay: .2s; largeur: 80%; & __ p-2 animation-delay: .3s; largeur: 70%;Ensuite, nous mettons à jour quelques lignes pour afficher l’espace réservé pendant la demande AJAX, comme suit:.
/ ** * Initialiser. * @retour vide * / init: function () this.roofLine = Math.ceil (window.innerHeight * 0.4); this.siteFloor = $ (this.settings.floor); this.addPlaceholder (); this.fetch (); this.scroller (); , / ** * Ajoutez le addPlaceholder. * L'espace réservé est utilisé pour indiquer qu'un nouveau message est en cours de chargement. * @return Void * / addPlaceholder: function () var tmplPlaceholder = document.getElementById ("tmpl-placeholder"); tmplPlaceholder = tmplPlaceholder.innerHTML; $ (this.element) .append (tmplPlaceholder); , / ** * Fonction pour récupérer et ajouter un nouvel article. * @return Void * / fetch: function () … // Sélectionnez l'élément qui enveloppe l'article. var main = this.element; $ .ajax (… beforeSend: function () … // Ajoute la classe 'd'extraction'. $ (main) .addClass (function () return "fetching";);)) always (function () … // Supprime la classe 'd'extraction'. $ (Main) .removeClass (fonction () return "extraction";););C'est comme ça que nous gérons l'espace réservé! Notre plugin est complet, et il est temps de déployer le plugin.
Déploiement
Le déploiement du plugin est assez simple. Nous désignons l'élément qui englobe notre article de blog et appelons notre plugin avec le jeu d'options, comme suit.
$ (document) .ready (function () $ ("#main") .keepScrolling (floor: "#footer", article: ".article", données: ["id": 1, "adresse": "post-one", "title": "Post One", "id": 2, "adresse": "post-deux", "title": "Post Two", "id": 3, "adresse": "post-trois", "titre": "Post trois", "id": 4, "adresse": "post-quatre", "titre": "Post Four", "id ": 5," adresse ":" post-cinq "," titre ":" Post Five "]););Le parchemin infini devrait maintenant fonctionner.
Mise en garde: le bouton de retour
Dans ce tutoriel, nous avons construit une expérience de défilement infini; quelque chose que nous avons souvent vu sur des sites de nouvelles comme Quartz, TechInAsia et dans de nombreuses applications mobiles.
Même s’il s’est avéré qu’il s’agissait d’un moyen efficace de conserver l’engagement des utilisateurs, il comporte également un inconvénient: il casse le bouton «Retour» dans le navigateur. Lorsque vous cliquez sur le bouton, il ne vous ramène pas toujours avec précision au contenu ou à la page précédemment visité (e)..
Les sites Web abordent ce problème de différentes manières. Quartz, par exemple, vous redirigera vers le référé URL l'URL que vous avez déjà visitée, mais pas celle enregistrée via l'API d'historique Web. TechInAsia vous ramènera simplement à la page d'accueil.
Emballer
Ce tutoriel est long et couvre beaucoup de choses! Certaines sont faciles à comprendre, alors que d'autres ne sont pas aussi faciles à digérer. Pour vous aider, j'ai dressé une liste de références en complément de cet article..
- Manipulation de l'historique du navigateur
- Transitions de page agréables et fluides avec l'API History Web
- Quelqu'un peut-il expliquer le "rebond"? fonction en Javascript
- AJAX pour les concepteurs front-end
- Développement de plug-in jQuery: meilleures pratiques
Enfin, examinez le code source complet et visionnez la démo.!