Maison > interface Web > js tutoriel > le corps du texte

Explication détaillée des paradigmes de programmation dans jQuery_jquery

WBOY
Libérer: 2016-05-16 16:27:01
original
1463 Les gens l'ont consulté

Cet article analyse en détail le paradigme de programmation dans jQuery. Partagez-le avec tout le monde pour votre référence. Les détails sont les suivants :

Le visage de la programmation frontale des navigateurs a subi de profonds changements depuis 2005. Cela ne signifie pas simplement qu'un grand nombre de bibliothèques de base dotées de fonctions riches ont émergé, nous permettant d'écrire du code métier plus facilement. a été un changement majeur dans la façon dont nous envisageons la technologie front-end, avec une conscience claire de la manière de libérer la productivité des programmeurs d'une manière spécifique au front-end. Ici, nous donnerons une brève introduction aux paradigmes de programmation et aux techniques courantes émergentes en JavaScript basées sur les principes d'implémentation du code source jQuery.

1. AJAX : persistance de l'état, mise à jour asynchrone

Tout d’abord, un peu d’histoire.

A. En 1995, Brendan Eich de Netscape a développé le langage JavaScript, qui est un langage de script dynamique, faiblement typé, basé sur un prototype.
B. En 1999, Microsoft IE5 a été lancé, qui incluait le contrôle XMLHTTP ActiveX.
C. Microsoft IE6 a été publié en 2001, prenant en charge partiellement les normes DOM niveau 1 et CSS 2.
D. Douglas Crockford a inventé le format JSON en 2002.

À ce stade, on peut dire que les éléments techniques sur lesquels repose le Web 2.0 ont pour l'essentiel pris forme, mais cela n'a pas eu immédiatement un impact significatif sur l'ensemble de l'industrie. Bien que certaines techniques de "rafraîchissement partiel asynchrone des pages" circulent secrètement parmi les programmeurs et aient même donné naissance à d'énormes bibliothèques de classes volumineuses comme bindows, en général, le front-end est considéré comme un marécage aride et sale, où seule la technologie backend est reine. Que manque-t-il?

Quand nous regardons le code js avant 2005 du point de vue d'aujourd'hui, y compris ceux écrits par des personnes talentueuses à cette époque, nous pouvons clairement ressentir leur faiblesse dans le contrôle des programmes. Ce n’est pas que la technologie js d’avant 2005 avait des problèmes en soi, c’est juste qu’elles étaient dispersées au niveau conceptuel, manquant d’un concept unifié ou manquant de leur propre style et âme. À cette époque, la plupart des gens et la plupart des technologies essayaient de simuler les langages orientés objet traditionnels et d'utiliser les technologies orientées objet traditionnelles pour implémenter des imitations des modèles d'interface graphique traditionnels.

2005 a été une année de changement et une année de création de concepts. Avec la sortie d'une série d'applications interactives rafraîchissantes par Google, un article « Ajax : A New Approach to Web Applications » de Jesse James Garrett a été largement diffusé. Ajax, un concept spécifique au front-end, a rapidement unifié de nombreuses pratiques dispersées sous le même slogan, déclenchant un changement de paradigme dans la programmation Web. Comme le dit le proverbe, si le nom n’est pas correct, les mots ne le seront pas. Désormais, les masses inconnues peuvent trouver une organisation. Avant Ajax, les gens reconnaissaient depuis longtemps que la caractéristique essentielle de l'architecture B/S était que les espaces d'état du navigateur et du serveur étaient séparés. Cependant, la solution générale consistait à masquer cette distinction et à synchroniser l'état de premier plan avec celui d'arrière-plan. Traitement logique unifié, tel qu'ASP.NET. En raison du manque de modèles de conception matures pour prendre en charge la persistance de l'état de premier plan, l'objet js chargé sera forcé d'être supprimé lors du changement de page. De cette façon, qui peut s'attendre à ce qu'il accomplisse un travail compliqué ?

Ajax indique clairement que l'interface est partiellement rafraîchie et que l'état réside au premier plan, ce qui favorise un besoin : les objets js doivent exister au premier plan plus longtemps. Cela signifie également la nécessité de gérer efficacement ces objets et fonctions, ce qui signifie une technologie d'organisation du code plus complexe, ce qui signifie le désir de modularité et d'une base de code commune.

Il y a en fait très peu de parties du code existant de jQuery qui sont réellement liées à Ajax (en utilisant des contrôles XMLHTTP pour accéder de manière asynchrone aux données de retour en arrière-plan), mais sans Ajax, jQuery n'aurait aucune raison d'exister en tant que base de code publique.

2. Modularisation : gestion des espaces de noms

Lorsqu'une grande quantité de code est générée, le concept le plus fondamental dont nous avons besoin est la modularisation, qui consiste à décomposer et à réutiliser le travail. La clé de la décomposition du travail est que les résultats du travail indépendant de chacun peuvent être intégrés ensemble. Cela signifie que chaque module doit être basé sur un concept sous-jacent cohérent et pouvoir interagir, c'est-à-dire qu'il doit être basé sur une base de code commune, protéger l'incohérence du navigateur sous-jacent et implémenter une couche d'abstraction unifiée, telle qu'une couche d'abstraction unifiée. mécanisme de gestion d’événements unifié. Plus important qu'une base de code unifiée, il ne doit y avoir aucun conflit de noms entre les modules. Sinon, les deux modules ne fonctionneront pas ensemble même sans aucune interaction entre eux.

L'un des principaux arguments de vente promus actuellement par jQuery est son bon contrôle sur les espaces de noms. C'est encore plus important que de fournir des points de fonction de plus en plus complets. Une bonne modularité nous permet de réutiliser le code de n'importe quelle source, et le travail de chacun peut être accumulé et superposé. Et la mise en œuvre des fonctions n’est qu’une question de charge de travail temporaire. jQuery utilise une variante du modèle de module pour réduire l'impact sur l'espace de noms global, en ajoutant uniquement un objet jQuery (c'est-à-dire $function) à l'objet window.

Le code du modèle de module est le suivant. La clé est d'utiliser des fonctions anonymes pour limiter la portée des variables temporaires.

Copier le code Le code est le suivant :
var feature =(function() {

//Variables et fonctions privées
var privateThing = 'secret',
PublicThing = 'pas secret',

changePrivateThing = function() {
        privateThing = 'super secret';
},

sayPrivateThing = function() {
console.log(privateThing);
         changePrivateThing();
};

// Retour à l'API publique
revenir {
chose publique : chose publique,
sayPrivateThing : sayPrivateThing
>
})();

JS lui-même n'a pas de structure de package, mais après des années de tentatives, l'industrie a progressivement unifié sa compréhension du chargement de packages, formant une solution comme la bibliothèque RequireJs qui a acquis un certain consensus. jQuery peut être bien intégré à la bibliothèque RequireJS pour obtenir une gestion plus complète des dépendances des modules. http://requirejs.org/docs/jquery.html

Copier le code Le code est le suivant :
require(["jquery", "jquery.my"], function () {
//Exécuter lorsque jquery.js et jquery.my.js sont chargés avec succès
$(fonction(){
​​​ $('#my').myFunc();
});
});


Le module my/shirt est défini via l'appel de fonction suivant, qui dépend des modules my/cart et my/inventory,
Copier le code Le code est le suivant :
require.def("my/shirt",
["mon/panier", "mon/inventaire"],
Fonction (panier, inventaire) {
// Utilisez le modèle de module ici pour renvoyer l'API exposée par le module my/shirt
         revenir {
            couleur : "bleu",
taille : "grand"
                addToCart: function() {
// décrémenter est l'API exposée par my/inventory
Inventaire.decrement(this);
                  cart.add(this);
            }
>
>
);

3. Magic$ : Promotion d'objets

À quoi avez-vous pensé lorsque vous avez vu pour la première fois la fonction $ ? La théorie de la programmation traditionnelle nous dit toujours que la dénomination des fonctions doit être précise et doit exprimer clairement l'intention de l'auteur. Elle affirme même que les noms longs sont meilleurs que les noms courts, car ils réduisent les risques d'ambiguïté. Mais qu’est-ce que $ ? Code tronqué ? Le message qu'il véhicule est trop obscur et ambigu. $ a été inventé par la bibliothèque prototype.js et est véritablement une fonction magique car elle peut transformer un nœud DOM primitif en un objet au comportement complexe. Dans l'implémentation originale de prototype.js, la fonction $ était définie comme

Copier le code Le code est le suivant :
var $ = function (id) {
Renvoie "string" == typeof id ? document.getElementById(id) : id;
};

Cela correspond en gros à la formule suivante
e = $(id)

Il ne s'agit pas seulement d'une abréviation intelligente du nom de fonction, mais plus important encore, elle établit une correspondance biunivoque entre l'identifiant du texte et l'élément DOM au niveau conceptuel. Avant qu'il y ait $, la distance entre l'identifiant et l'élément correspondant est très grande. Généralement, l'élément doit être mis en cache dans une variable, telle que
.

Copier le code Le code est le suivant :
var ea = docuement.getElementById('a');
var eb = document.getElementById('b');
chaque style....

Mais après avoir utilisé $, vous pouvez voir l'écriture suivante partout
Copier le code Le code est le suivant :
$('header_' id).style...
$(identifiant 'body_')....

La distance entre l’identifiant et l’élément semble être éliminée et ils peuvent être très étroitement liés.

prototype.js a ensuite élargi la signification de $,

Copier le code Le code est le suivant :
fonction $() {
var éléments = new Array();
 
pour (var i = 0; i < arguments.length; i ) {
        var element = arguments[i];
Si (type d'élément == 'string')
            element = document.getElementById(element);
 
           if (arguments.length == 1)
           élément de retour ;
 
        elements.push(element);
>
 
Éléments de retour ;
>

Cela correspond à la formule :
[e,e] = $(id,id)

Malheureusement, prototype.js s'est égaré dans cette étape, et cette approche a peu de valeur pratique.
C'est jQuery qui promeut vraiment le $, et son $ correspond à la formule
[o] = $(sélecteur)
Voici trois améliorations :
A. Le sélecteur n'est plus un localisateur de nœud unique, mais un sélecteur de collection complexe
B. Les éléments renvoyés ne sont pas des nœuds DOM d'origine, mais des objets aux comportements riches encore améliorés par jQuery, qui peuvent démarrer des chaînes d'appels de fonctions complexes.
C. L'objet d'empaquetage renvoyé par $ est mis en forme sous forme de tableau, qui intègre naturellement les opérations de collecte dans la chaîne d'appel.

Bien sûr, ce qui précède n'est qu'une description trop simpliste du $ magique, et sa fonction réelle est beaucoup plus compliquée. En particulier, il existe une fonction de construction directe très couramment utilisée
.

Copier le code Le code est le suivant :
$("
")....

jQuery construira directement une série de nœuds DOM basés sur le texte html entrant et les conditionnera en tant qu'objets jQuery dans une certaine mesure : la description du contenu html elle-même est une désignation unique.

$(function{}) Cette fonction est vraiment un peu sans voix. Cela signifie que cette fonction de rappel est appelée lorsque document.ready. Vraiment, $ est une fonction magique. Si vous avez des questions, n'hésitez pas.

Pour résumer, $ est le canal de transition du monde ordinaire du DOM et de la description textuelle vers le monde jQuery avec un comportement d'objet riche. Après avoir franchi cette porte, nous sommes arrivés à l'Utopie.

4. Paramètres amorphes : se concentrer sur l'expression plutôt que sur les contraintes

Étant donné que les langues faiblement typées ont le mot « faible » sur la tête, il est inévitable que les gens se sentent un peu déficients de manière innée. Le manque de contraintes de type dans le programme est-il vraiment une lacune majeure dans les langues traditionnelles fortement typées ? , le type et le nombre de paramètres de fonction sont toutes des contraintes vérifiées par le compilateur, mais ces contraintes sont encore loin d'être suffisantes. Dans les applications générales, afin de renforcer les contraintes, une grande quantité de code défensif est toujours ajoutée, comme en C We. utilise couramment ASSERT, et en Java, nous devons souvent déterminer la plage de valeurs des paramètres

Copier le code Le code est le suivant :
if (index < 0 || index >= taille)
          lancer une nouvelle exception IndexOutOfBoundsException(
"Index : " index ", Taille : " taille);

Évidemment, ces codes conduiront à un grand nombre de chemins d'exécution non fonctionnels dans le programme, c'est-à-dire que nous avons fait beaucoup de jugements, et lorsque le code est exécuté jusqu'à un certain point, le système lève une exception en criant que ce chemin est bloqué. Si nous changeons notre façon de penser, puisque nous avons effectué certains jugements, pouvons-nous utiliser les résultats de ces jugements pour faire quelque chose ? JavaScript est un langage faiblement typé. Il ne peut pas automatiquement contraindre les types de paramètres. et affaiblir davantage la forme des paramètres, la « faiblesse » a été poussée à l'extrême Quand il n'y a rien de faible à faire, la faiblesse deviendra-t-elle une caractéristique emblématique ?

Regardez la fonction de liaison d'événement bind dans jQuery,
A. Lier un événement à la fois

Copier le code Le code est le suivant :
$("#my") .bind(" mouseover ", function(){});

B. Lier plusieurs événements à la fois
Copier le code Le code est le suivant :
$("#my") .bind( "mouseover mouseout",function(){})

C. Changez le formulaire et liez plusieurs événements
Copier le code Le code est le suivant :
$("#my").bind({mouseover:function( ){} , mouseout:function(){});

D. Vous souhaitez transmettre certains paramètres à l'écouteur d'événement
Copier le code Le code est le suivant :
$('#my').bind('click', { foo: " xxxx"}, function(event) { event.data.foo..})

E. Vous souhaitez regrouper les auditeurs d'événements
Copier le code Le code est le suivant :
$("#my").bind("click.myGroup" , function( ){});

F. Pourquoi cette fonction n'est-elle pas devenue folle ???

Même si le type est incertain, la signification des paramètres à des positions fixes doit être certaine, n'est-ce pas ? En prenant du recul, même si la position du paramètre n'est pas importante, la signification de la fonction elle-même devrait être certaine, n'est-ce pas ? ça ? Valeur valeur = o.val(), définissez la valeur o.val(3)

       
Comment une fonction peut-elle être aussi excessive, comment peut-elle se comporter différemment selon le type et le nombre de paramètres transmis ? N'est-ce pas désagréable à l'œil ? . Bien qu'il existe de nombreuses formes de changement, mais pas un mot de bêtise. Le manque de retenue n'empêche pas l'expression (je ne suis pas là pour effrayer les gens
).

5. Fonctionnement en chaîne : affinement progressif de la linéarisation

Le principal argument de vente de jQuery au début était ce qu'on appelle l'opération en chaîne

.

Copier le code Le code est le suivant :
$('#content') // Rechercher l'élément de contenu
.find('h3') // Sélectionnez tous les nœuds h3 descendants
.eq(2) // Filtrer la collection et conserver le troisième élément
​​​​.html('Changer le texte du troisième h3')
.end() // Retour à la collection h3 précédente
.eq(0)
​​​​.html('Changer le texte du premier h3');

Dans les langages impératifs généraux, nous devons toujours filtrer les données dans des boucles imbriquées, et le code permettant d'exploiter réellement les données est intriqué avec le code permettant de localiser les données. Cependant, jQuery utilise d'abord la méthode de construction d'une collection, puis de l'appliquer. fonctions à la collection. Cette méthode réalise le découplage des deux logiques et la linéarisation de la structure imbriquée. En fait, nous pouvons comprendre intuitivement une collection sans recourir à la pensée procédurale, telle que $('div.my input:checked') Peut être considéré comme une description directe plutôt que comme un suivi du comportement du processus.

La boucle signifie que notre pensée est dans un état de rembobinage répété, et après linéarisation, elle va directement dans une direction, ce qui réduit considérablement la charge de réflexion et améliore la composabilité du code afin de réduire l'interruption de l'appel. chain , jQuery a inventé une idée merveilleuse : jQuery encapsule l'objet lui-même comme un tableau (une collection) peut être mappée à de nouvelles collections et les collections peuvent être limitées à leurs propres sous-collections. L'initiateur de l'appel est une collection et celle renvoyée. Le résultat est également une collection. Les collections peuvent avoir lieu. Certains changements structurels ont eu lieu, mais c'est toujours un ensemble. Un ensemble est un point fixe conceptuel. Il s'agit d'une idée de conception absorbée par les langages fonctionnels. Les opérations de collection sont des opérations trop courantes. En Java, nous pouvons facilement constater qu'un grand nombre de fonctions dites d'encapsulation encapsulent en fait certaines opérations de traversée de collection. Dans jQuery, les opérations de collection sont trop simples et n'ont pas besoin d'être encapsulées.

Les appels chaînés signifient que nous avons toujours un objet "courant", et que toutes les opérations sont effectuées sur cet objet courant. Cela correspond à la formule suivante
x = dx
Chaque étape de la chaîne d'appels est une description incrémentielle de l'objet actuel et un processus de raffinement étape par étape vers l'objectif final. Cette idée est également largement utilisée dans la plateforme Witrix. Surtout afin de réaliser l'intégration du mécanisme de la plateforme et du code métier, la plateforme fournira le contenu par défaut de l'objet (conteneur), et le code métier pourra être progressivement affiné et révisé sur cette base, y compris l'annulation des paramètres par défaut.

Cela dit, bien que l'appel en chaîne de jQuery soit très simple en apparence, vous devez écrire une couche supplémentaire de boucles lors de son implémentation en interne, car le compilateur ne sait pas "s'appliquer automatiquement à chaque élément de la collection".

Copier le code Le code est le suivant :
$.fn['someFunc'] = function(){
Renvoie this.each(function(){
​​ jQuery.someFunc(this,...);
>
>


6. données : gestion unifiée des données

En tant que bibliothèque js, un gros problème qu'elle doit résoudre est l'association d'état et la gestion collaborative entre les objets js et les nœuds DOM. Certaines bibliothèques js choisissent de se concentrer sur les objets js et enregistrent les pointeurs de nœuds DOM dans les variables membres des objets js lors de l'accès, elles utilisent toujours les objets js comme point d'entrée et exploitent indirectement les objets DOM via les fonctions js. Dans ce type d'encapsulation, le nœud DOM n'est en réalité qu'un « assemblage » de bas niveau affiché sous forme d'interface. Le choix de jQuery est similaire à la plate-forme Witrix, qui est basée sur la structure HTML elle-même. Elle améliore la fonction du nœud DOM via js et le promeut en un objet étendu au comportement complexe. L'idée ici est une conception non intrusive (non intrusive) et un mécanisme de dégradation gracieuse (dégradation gracieuse). La structure sémantique est complète au niveau HTML de base. Le rôle de js est d'améliorer le comportement interactif et de contrôler le formulaire de présentation.

Si nous accédons à chaque fois à l'objet d'emballage correspondant via $('#my'), où sont stockées certaines variables d'état qui doivent être conservées pendant une longue période ? jQuery fournit un mécanisme global unifié de gestion des données.

Obtenir des données :

Copier le code Le code est le suivant :
$('#my').data ('monAttr')

Définir les données :
Copier le code Le code est le suivant :
$('#my').data('myAttr ',3 );

Ce mécanisme intègre naturellement le traitement des attributs des données HTML5
Copier le code Le code est le suivant :

L'ensemble de données en HTML peut être lu via $('#my').data('myAttr').

Lors du premier accès aux données, jQuery attribuera un uuid unique au nœud DOM, puis le définira sur un attribut expando spécifique du nœud DOM jQuery garantit que cet uuid n'est pas répété dans cette page.

Copier le code Le code est le suivant :
elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

Le code ci-dessus peut gérer à la fois les nœuds DOM et les objets js purs. S'il s'agit d'un objet js, les données sont placées directement dans l'objet js lui-même, et s'il s'agit d'un nœud DOM, elles sont gérées uniformément via le cache.

Étant donné que toutes les données sont gérées de manière uniforme via le mécanisme de données, en particulier toutes les fonctions d'écoute d'événements (data.events), jQuery peut implémenter la gestion des ressources en toute sécurité. Lors du clonage d'un nœud, ses fonctions d'écoute d'événements associées peuvent être automatiquement clonées. Lorsque le contenu du nœud DOM est remplacé ou que le nœud DOM est détruit, jQuery peut également annuler automatiquement la fonction d'écoute des événements et libérer en toute sécurité les données js pertinentes.

7. événement : modèle d'événement unifié

L'image des « événements se propageant le long de l'arborescence des objets » est l'essence du modèle de programmation d'interface orientée objet. La composition des objets constitue une description stable de la structure de l'interface. Les événements se produisent continuellement à un certain nœud de l'arborescence des objets et se propagent vers le haut à travers le mécanisme de bouillonnement. L'arborescence d'objets devient naturellement une structure de contrôle. Nous pouvons écouter les événements sur tous les nœuds enfants du nœud parent sans établir explicitement une association avec chaque nœud enfant.

En plus d'établir une abstraction unifiée pour les modèles d'événements des différents navigateurs, jQuery a principalement apporté les améliorations suivantes :
A. Ajout d'un mécanisme d'événement personnalisé (personnalisé). Le mécanisme de propagation des événements n'a en principe rien à voir avec le contenu de l'événement lui-même, de sorte que les événements personnalisés peuvent passer par le même chemin de traitement et utiliser la même méthode de surveillance que les événements intégrés du navigateur. . Utiliser des événements personnalisés peut améliorer la cohésion du code et réduire le couplage de code. Par exemple, s'il n'y a pas d'événements personnalisés, le code associé doit souvent faire fonctionner directement les objets associés
.

Copier le code Le code est le suivant :
$('.switch, .clapper').click(function( ) {
var $light = $(this).parent().find('.lightbulb');
Si ($light.hasClass('on')) {
          $light.removeClass('on').addClass('off');
} autre {
          $light.removeClass('off').addClass('on');
>
});

Si vous utilisez des événements personnalisés, la sémantique exprimée est plus sobre et claire,
Copier le code Le code est le suivant :
$('.switch, .clapper').click(function( ) {
$(this).parent().find('.lightbulb').trigger('changeState');
});

B. Ajout de la surveillance des événements pour les nœuds créés dynamiquement. La fonction de liaison ne peut enregistrer les fonctions d'écoute que sur les nœuds DOM existants. Par exemple
.
Copier le code Le code est le suivant :
$('li.trigger').bind('click', fonction() {}}

Si un autre nœud li est créé après avoir appelé bind, l'événement click de ce nœud ne sera pas surveillé.

Le mécanisme délégué de jQuery peut enregistrer la fonction d'écoute sur le nœud parent, et les événements déclenchés sur le nœud enfant seront automatiquement envoyés au handlerFn correspondant en fonction du sélecteur. De cette façon, si vous vous inscrivez maintenant, vous pouvez écouter. les nœuds créés dans le futur
.

Copier le code Le code est le suivant :
$('#myList').delegate('li.trigger' , 'cliquez', handlerFn);

Récemment, jQuery 1.7 a unifié les mécanismes de liaison, de direct et de délégation, et le monde est unifié, uniquement activé/désactivé.

Copier le code Le code est le suivant :
$('li.trigger').on('click', handlerFn); // Équivalent à bind
$('#myList').on('click', 'li.trigger', handlerFn); // Équivalent à délégué

 
8. File d'attente d'animation : coordination de l'horloge mondiale

En mettant de côté l'implémentation de jQuery, réfléchissons d'abord à ce que nous devons faire si nous voulons obtenir des effets d'animation sur l'interface. Par exemple, nous voulons augmenter la largeur d'un div de 100 px à 200 px en 1 seconde ? Il est facile d'imaginer que sur une période de temps, nous devons ajuster la largeur du div de temps en temps, [et en même temps] nous devons également exécuter d'autres codes. Contrairement aux appels de fonction ordinaires, après avoir émis la commande d'animation, nous Nous ne pouvons pas nous attendre à obtenir immédiatement ce que nous voulons. Le résultat, et nous ne pouvons pas simplement attendre que le résultat arrive. La complexité de l'animation réside dans le fait qu'elle doit être exécutée dans un certain laps de temps après une expression unique, et il y en a. plusieurs chemins d'exécution logiques qui doivent être dépliés en même temps. Comment coordonner ?

Le grand Sir Isaac Newton a écrit dans "Principes mathématiques de la philosophie naturelle" : "Le temps absolu, vrai et mathématique lui-même passe". Tous les événements peuvent être alignés sur la chronologie, ce qui est leur coordination inhérente afin d'exécuter les étapes. A1 à A5 et les étapes B1 à B5 en même temps, il suffit d'exécuter [A1, B1] au temps t1, [A2, B2] au temps t2, et ainsi de suite. t1 | t2 | t3 | t4 | t5 ...

A1 | A2 | A3 | A4 | B1 | B2 | B3 | B4 | B5...

Un formulaire spécifique de mise en œuvre peut être
A. Pour chaque animation, divisez-la en un objet Animation, qui est divisé en plusieurs étapes en interne.

animation = nouvelle Animation(div,"largeur",100,200,1000,

La fonction d'interpolation responsable de la segmentation des étapes et la fonction de rappel lorsque l'animation est terminée) ; B. Enregistrez l'objet d'animation dans le gestionnaire global
timerFuncs.add(animation);
C. A chaque instant de déclenchement de l'horloge globale, avancez d'un pas chaque séquence d'exécution enregistrée, et si elle est terminée, supprimez-la du gestionnaire global
.



Copier le code

Le code est le suivant :pour chaque animation dans timerFuncs           if(!animation.doOneStep())            timerFuncs.remove(animation)


Après avoir résolu le problème principal, examinons le problème d'expression. Comment concevoir des fonctions d'interface pour exprimer nos intentions sous la forme la plus compacte que nous rencontrons souvent :
A. Il existe plusieurs éléments pour réaliser des animations similaires

B. Chaque élément a plusieurs attributs qui doivent changer en même temps
C. Après avoir exécuté une animation, démarrez une autre animation

On peut dire que les réponses de jQuery à ces questions éliminent la dernière valeur restante de l’expression grammaticale de js

.



Copier le code

Le code est le suivant :$('input') .animate({left:' =200px',top:'300'},2000) .animate({left:'-=200px',top:20},1000)
.queue(function(){
//Ici, dequeue exécutera d'abord la dernière fonction de la file d'attente, donc alert("y")
         $(this).dequeue();
alerte('x');
})
.queue(function(){
alert("y");
// Si vous ne retirez pas activement la file d'attente, l'exécution de la file d'attente sera interrompue et ne continuera pas automatiquement.
           $(this).dequeue();
});

A. Utilisez le mécanisme de sélection intégré de jQuery pour exprimer naturellement le traitement d'une collection.
B. Utilisez Map pour exprimer plusieurs changements d'attributs
C. Utiliser des microformats pour exprimer des concepts delta spécifiques au domaine ' =200px' signifie ajouter 200px à la valeur existante
. D. Utilisez l'ordre des appels de fonction pour définir automatiquement l'ordre d'exécution de l'animation : les animations ajoutées à la file d'attente d'exécution attendront naturellement que l'animation précédente soit complètement exécutée avant de démarrer.

Les détails d'implémentation de la file d'attente d'animation jQuery sont à peu près les suivants,

A. La fonction animer appelle en fait queue(function(){dequeue doit être appelée à la fin de l'exécution, sinon la méthode suivante ne sera pas pilotée})
Lorsque la fonction de file d'attente est exécutée, s'il s'agit d'une file d'attente fx et qu'aucune animation n'est en cours d'exécution (si animate est appelée deux fois de suite, la deuxième fonction d'exécution attendra dans la file d'attente), l'opération de sortie de file d'attente sera automatiquement déclenchée pour piloter le file d'attente pour courir.
S'il s'agit d'une file d'attente fx, la chaîne "inprogress" sera automatiquement ajoutée en haut de la file d'attente lors du retrait de la file d'attente, indiquant que l'animation est sur le point d'être exécutée
. B. Pour chaque propriété, créez un objet jQuery.fx. Appelez ensuite la fonction fx.custom (équivalent à start) pour démarrer l'animation.
C. Dans la fonction personnalisée, enregistrez la fonction fx.step dans le timerFuncs global, puis essayez de démarrer une minuterie globale.
timerId = setInterval( fx.tick, fx.interval );
D. La fonction tick statique appellera la fonction step de chaque fx dans l'ordre. Dans la fonction step, la valeur actuelle de l'attribut est calculée par assouplissement, puis la mise à jour de fx est appelée pour mettre à jour l'attribut.
E. La fonction step de fx détermine que si tous les changements d'attribut ont été effectués, dequeue est appelé pour piloter la méthode suivante.

Ce qui est très intéressant, c'est qu'il y a évidemment de nombreux codes de déclenchement de relais dans le code d'implémentation de jQuery : si vous devez exécuter l'animation suivante, retirez-la et exécutez-la, si vous devez démarrer le timer, démarrez le timer, etc. En effet, le programme js est monothread. Il n'y a qu'un seul véritable chemin d'exécution. Afin de garantir que le thread d'exécution ne soit pas interrompu, les fonctions doivent s'entraider. moteurs à l'intérieur du programme, ou même des moteurs d'exécution infinis, alors l'apparence du programme changera fondamentalement. Dans ce cas, la récursion deviendra une description plus naturelle par rapport à la boucle
.
9. Modèle de promesse : identification des relations causales

En réalité, il y a toujours tellement de lignes temporelles évoluant indépendamment, et les personnes et les choses se croisent dans le temps et l'espace, mais aucune cause et effet ne se produisent dans les logiciels, les fonctions sont alignées dans le code source, et certaines questions se poseront inévitablement. .Pourquoi celui qui est au premier plan devrait-il être exécuté en premier ? N'y aurait-il pas moi sans lui ? Que l'univers entier avance à l'unisson en criant 1, 2, 3. Du point de vue de Dieu, la gestion est probablement trop difficile, alors là est la théorie de la relativité. S'il n'y a pas d'échange d'informations et pas de dépendance mutuelle, alors les événements qui se produisent séquentiellement dans un système de coordonnées peuvent sembler être dans l'ordre inverse lorsqu'ils sont visualisés dans un autre système de coordonnées. puis j'ai inventé le modèle de promesse.

Les modèles de promesse et les modèles futurs sont fondamentalement la même chose. Jetons d'abord un coup d'œil au modèle futur familier en Java.

Copier le code Le code est le suivant :
futureResult = doSomething();
...
realResult = futureResult.get();

Émettre un appel de fonction signifie uniquement que quelque chose s'est produit, et ne signifie pas nécessairement que l'appelant a besoin de connaître le résultat final de l'affaire. Ce que la fonction renvoie immédiatement n'est qu'une promesse (de type Future) qui sera remplie dans. le futur, qui est en fait une sorte de handle.Le handle est transmis, et le code qui change de main au milieu est indifférent au résultat réel et s'il a été renvoyé jusqu'à ce qu'un morceau de code doive s'appuyer. le résultat renvoyé par l'appel, il ouvre donc le futur et le vérifie. Si le résultat réel a été renvoyé, alors future.get() renvoie le résultat réel immédiatement, sinon il bloquera le chemin d'exécution actuel jusqu'à ce que le résultat soit renvoyé. L'appel de future.get() après cela reviendra toujours immédiatement, car la relation causale a été établie, [result return] Cet événement doit s'être produit avant cela et ne changera plus.

Le mode futur signifie généralement que l'objet externe vérifie activement la valeur de retour du futur, tandis que le mode promesse signifie que l'objet externe enregistre une fonction de rappel sur la promesse
.

Copier le code Le code est le suivant :
fonction getData(){
Renvoie $.get('/foo/').done(function(){
console.log('Se déclenche après la réussite de la requête AJAX');
}).fail(function(){
console.log('Se déclenche après l'échec de la requête AJAX');
});
>

fonction showDiv(){
var dfd = $.Deferred();
$('#foo').fadeIn( 1000, dfd.resolve );
Renvoie dfd.promise();
>

$.when( getData(), showDiv() )
.then(function(ajaxResult, ignoreResultFromShowDiv){
console.log('Les feux se déclenchent après que showDiv() ET la requête AJAX aient réussi !');
​​​​ // 'ajaxResult' est la réponse du serveur
});

jQuery introduit la structure Deferred, reconstruit ajax, queue, document.ready, etc. selon le mode promesse, et unifie le mécanisme d'exécution asynchrone puis (onDone, onFail) ajoutera une fonction de rappel à la promesse. l'appel est terminé avec succès ( résoudre), la fonction de rappel onDone sera exécutée, et si l'appel échoue (rejet), alors onFail sera exécuté quand il pourra attendre sur plusieurs objets de promesse. La chose intelligente à propos de la promesse est qu'après l'exécution asynchrone. a commencé voire terminé, Il est toujours possible d'enregistrer des fonctions de rappel

someObj.done(callback).sendRequest() contre someObj.sendRequest().done(callback)

Enregistrer la fonction de rappel avant d'émettre un appel asynchrone ou s'enregistrer après avoir émis un appel asynchrone est tout à fait équivalent. Cela révèle que l'expression du programme n'est jamais complètement exacte et qu'il y a toujours une dimension inhérente de changement si cette dimension inhérente peut être efficace. utilisé La variabilité peut grandement améliorer les performances des programmes simultanés.

L'implémentation spécifique du mode promesse est très simple. jQuery._Deferred définit une file d'attente de fonctions, qui a les fonctions suivantes :

A. Enregistrez la fonction de rappel.
B. Exécutez toutes les fonctions enregistrées au moment de la résolution ou du rejet.
C. Après son exécution, toutes les fonctions supplémentaires seront exécutées immédiatement.

Certains langages spécifiquement orientés vers le calcul distribué ou le calcul parallèle auront un mode promesse intégré au niveau du langage, comme le langage E
.

Copier le code Le code est le suivant :
def carPromise := carMaker <- Produce("Mercedes");
Def temperaturePromise := carPromise <- getEngineTemperature()
...
Quand (températurePromesse) -> terminé (température) {
           println(`La température du moteur de la voiture est : $temperature`)
} attrape e {
          println(`Impossible d'obtenir la température du moteur, erreur : $e`)
>

En langage E, <- est l'opérateur éventuellement, ce qui signifie qu'il sera exécuté éventuellement, mais pas nécessairement maintenant. L'ordinaire car.moveTo(2,3) signifie qu'il sera exécuté immédiatement et que le résultat sera obtenu. Le compilateur est chargé d'identifier toutes les dépendances des promesses et d'implémenter automatiquement la planification
.
10. étendre : L'héritage n'est pas nécessaire

JS est un langage basé sur un prototype et n'a pas de mécanisme d'héritage intégré. Cela a toujours dérangé de nombreux étudiants profondément formés dans l'enseignement traditionnel orienté objet. Mais que peut-il nous apporter ? La réponse la plus simple est : la réutilisation du code. Alors, analysons d'abord le potentiel de l'héritage comme moyen de réutilisation du code.

Il existait autrefois un concept appelé « héritage multiple », qui était la version Super Saiyan du concept d'héritage. Malheureusement, il a ensuite été diagnostiqué comme ayant une malformation congénitale, de sorte qu'une interprétation du concept d'héritage a émergé : l'héritage est " est une " relation, un objet dérivé " est un " a de nombreuses classes de base, ce qui mènera inévitablement à la schizophrénie, donc l'héritage multiple est mauvais
.

Copier le code Le code est le suivant :
class A{ public: void f(){ f in A } }
class B{ public: void f(){ f in B } }
classe D : public A, B{}

Si la classe D hérite de deux classes de base A et B, et que les deux classes A et B implémentent la même fonction f, alors le f de la classe D est le f dans A ou le f dans B, ou est-ce qu'en est-il de f dans A et f dans B ? L'émergence de ce dilemme vient en fait du fait que les classes de base A et B de D sont dans une relation parallèle. Elles satisfont à la loi commutative et à la loi associative. il peut être difficile pour nous de reconnaître que deux relations de subordination apparaîtront entre des concepts. Mais si nous assouplissons certaines exigences au niveau conceptuel et considérons les problèmes de réutilisation du code davantage du niveau opérationnel, nous pouvons simplement penser que B fonctionne sur la base de A, alors. on peut obtenir un résultat de transformation linéaire. Autrement dit, en abandonnant la loi commutative entre A et B et en ne conservant que la loi associative, étend A, B et étend B, A aura deux résultats différents, et il n'y aura plus. Il n'y a aucune ambiguïté dans l'interprétation. scala Le mécanisme dit de trait dans le langage adopte en fait cette stratégie.

Longtemps après l'invention de la technologie orientée objet, la programmation dite orientée aspect (AOP) est apparue. Elle est différente de la POO en ce sens qu'il s'agit d'une technologie de positionnement et de modification dans l'espace de la structure du code. et les méthodes, et ne sait pas ce que signifie . AOP fournit également une méthode de réutilisation de code similaire à l'héritage multiple, qui est le mixin. L'objet est considéré comme une carte qui peut être ouverte et modifiée arbitrairement. sont directement injectés dans le corps de l'objet et modifient directement son comportement
. La bibliothèque prototype.js introduit la fonction d'extension,

Copier le code Le code est le suivant :
Object.extend = function(destination, source) {
pour (propriété var dans la source) {
destination[propriété] = source[propriété];
>
Destination de retour ;
>

est une opération de couverture entre Maps, mais elle est très efficace et a été étendue dans la bibliothèque jQuery. Cette opération est similaire au mixin, qui est le principal moyen technique de réutilisation de code dans jQuery --- ce n'est pas grave. s'il n'y a pas d'héritage de.

11. Mappage de noms : tout est données

Si le code est bon, il doit y avoir moins de jugements de boucles. Les boucles et les instructions de jugement sont les composants de base du programme, mais on ne les trouve souvent pas dans les excellentes bibliothèques de code, car l'entrelacement de ces instructions brouillera la ligne principale. de la logique du système. Laissez nos esprits se perdre dans le traçage épuisant du code. jQuery lui-même a considérablement réduit le besoin d'instructions de boucle via des fonctions telles que each et extend. Pour les instructions de jugement, elles sont principalement traitées via des tables de mappage. La fonction val() de jQuery doit effectuer un traitement différent pour différentes balises, définissez donc une table de mappage de fonctions avec tagName comme clé

Copier le code Le code est le suivant :
valHooks : { option : {get:function(){}}}

De cette façon, vous n'avez pas besoin d'écrire
partout dans le programme
Copier le code Le code est le suivant :
if(elm.tagName == 'OPTION'){
Retour...;
}else if(elm.tagName == 'TEXTAREA'){
Retour...;
>

Peut être traité de manière unifiée
Copier le code Le code est le suivant :
(valHooks[elm.tagName.toLowerCase()] || defaultHandler) .get( orme);


Les tables de mappage gèrent les fonctions comme des données ordinaires et sont largement utilisées dans les langages dynamiques. En particulier, l'objet lui-même est un conteneur de fonctions et de variables et peut être considéré comme une table de mappage. Une technique largement utilisée dans jQuery consiste à utiliser le mappage de noms vers de manière dynamique. générer du code, formant un mécanisme de type modèle. Par exemple, pour implémenter deux fonctions très similaires myWidth et myHeight, nous n'avons pas besoin de
.
Copier le code Le code est le suivant :
jQuery.fn.myWidth = function(){
Renvoie parseInt(this.style.width,10) 10;
>
 
jQuery.fn.myHeight = fonction(){
Retourner parseInt(this.style.height,10) 10;
>

Au lieu de cela, vous pouvez choisir de générer dynamiquement
Copier le code Le code est le suivant :
jQuery.each(['Largeur','Hauteur'],fonction(nom){
jQuery.fn['mon' nom] = function(){
           return parseInt(this.style[name.toLowerCase()],10) 10;
>
});


12. Mécanisme de plug-in : En fait, je suis très simple

Les soi-disant plug-ins de jQuery sont en fait des fonctions ajoutées à $.fn Alors, c'est quoi ce fn ?

Copier le code Le code est le suivant :
(fonction (fenêtre, non définie){
// Il y a un autre paquet à l'intérieur
var jQuery = (fonction() {
var jQuery = fonction (sélecteur, contexte) {
                   return new jQuery.fn.init (sélecteur, contexte, rootjQuery );
>
....
// fn est en fait l'abréviation de prototype
jQuery.fn = jQuery.prototype = {
​​​​​constructeur : jQuery,
            init : fonction (sélecteur, contexte, rootjQuery) {... }
>
 
// Appeler jQuery() équivaut à new init(), et le prototype de init est le prototype de jQuery
​​ jQuery.fn.init.prototype = jQuery.fn;
 
// // L'objet jQuery renvoyé ici n'a que les fonctions les plus basiques. Ce qui suit est une série de extend
. Retourner jQuery ;
})();
...
//Exposer jQuery en tant qu'objet global
​ window.jQuery = window.$ = jQuery;
})(fenêtre);

Évidemment, $.fn est en fait l'abréviation de jQuery.prototype
.
Un plug-in sans état n'est qu'une fonction, très simple
.

Copier le code Le code est le suivant :
// Définir le plugin
(fonction($){
$.fn.hoverClass = fonction(c) {
           renvoie this.hover(
                 function() { $(this).toggleClass(c }
); );
};
})(jQuery);

//Utiliser le plugin
$('li').hoverClass('hover');


Pour le développement de plug-ins plus complexes, jQuery UI fournit un mécanisme de fabrique de widgets,
Copier le code Le code est le suivant :
$.widget("ui.dialog", {
Options : {
        autoOpen : vrai,...
},
_create : function(){ ... },
_init : fonction() {
           if ( this.options.autoOpen ) {
This.open();
>
},
_setOption : fonction (clé, valeur){ ... }
          détruire : fonction(){ ... }
});


Lors de l'appel de $('#dlg').dialog(options), le code réel exécuté est essentiellement le suivant :
Copier le code Le code est le suivant :
this.each(function() {
         var instance = $.data( this, "dialog" );
          if ( instance ) {
Instance.option( options || {} )._init();
         } autre {
               $.data( this, "dialog", new $.ui.dialog( options, this ) );
>
>

On peut voir que la première fois que la fonction $('#dlg').dialog() est appelée, une instance d'objet window sera créée et enregistrée dans data. À ce moment, les fonctions _create() et _init() le seront. être appelée, et si si elle n'est pas appelée pour la première fois, la méthode _init() est appelée sur une instance d'objet existante. Appeler $('#dlg').dialog() plusieurs fois ne créera pas plusieurs instances.

13. Renifleur de navigateur vs détection de fonctionnalités

Le renifleur de navigateur était autrefois une technologie très populaire, comme aux débuts de jQuery

Copier le code Le code est le suivant :
jQuery.browser = {
Version :(userAgent.match(/. (?:rv|it|ra|ie)[/: ]([d.] )/) || [0,'0'])[1],
​​​ safari:/webkit/.test(userAgent),
​​​​opera:/opera/.test(userAgent),
          msie:/msie/.test(userAgent) && !/opera/.test(userAgent),
mozilla:/mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent)
};

Dans le code spécifique, différents traitements peuvent être effectués pour différents navigateurs

Copier le code Le code est le suivant :
if($.browser.msie) {
// faire quelque chose
} sinon si($.browser.opera) {
// ...
>

Cependant, à mesure que la concurrence sur le marché des navigateurs s'intensifie, les concurrents s'imitent et se déguisent, ce qui entraîne le chaos des userAgents. Couplé à la naissance de Chrome et à l'essor de Safari, IE a également commencé à accélérer son évolution vers les standards et les renifleurs. ne peut plus le faire. Effet positif. La détection de fonctionnalités (détection de fonctionnalités), en tant que méthode de détection plus fine et plus spécifique, est progressivement devenue le moyen courant de gérer la compatibilité des navigateurs.

Copier le code Le code est le suivant :
jQuery.support = {
// IE supprime les espaces de début lorsque .innerHTML est utilisé
​​​​leadingWhitespace : ( div.firstChild.nodeType === 3 ),
...
>
Uniquement sur la base de ce que vous avez réellement vu, plutôt que de ce que vous saviez autrefois, il est plus facile d'être compatible avec l'avenir.

14. Prototype contre jQuery

prototype.js est une bibliothèque aux nobles aspirations. Son objectif est de fournir une nouvelle expérience utilisateur, de transformer JavaScript du niveau du langage en référence à Ruby, et finalement de vraiment changer considérablement le visage de js. $, extends, each, bind... Ces concepts familiers sont tous introduits dans le champ js par prototype.js. Il ajoute sans scrupules divers concepts à l'espace de noms global de la fenêtre. Celui qui en profite en premier a raison. jQuery, en revanche, est plus pragmatique et son objectif est simplement d'écrire moins et de faire plus

.

Cependant, le sort qui attend les idéalistes radicaux est souvent de mourir avant que leurs ambitions ne soient réalisées. Lorsque la fonction de liaison emblématique de prototype.js a été absorbée dans le standard ECMAScript, son déclin était voué à l'échec. est la compétence secrète unique de prototype.js, et c'est aussi son talon d'Achille. Surtout lorsqu'il essaie d'imiter jQuery et renvoie des objets améliorés via Element.extend(element), il est complètement jeté dans le fossé par jQuery. est différent de jQuery, il modifie toujours directement le prototype de l'objet natif. Cependant, les navigateurs sont un domaine plein de bugs, de mensonges, de bagages historiques et de conspirations commerciales. La résolution des problèmes au niveau de l'objet natif est vouée à être une tragédie. les problèmes, les conflits de noms, les problèmes de compatibilité, etc. ne peuvent pas être résolus par la capacité d'une bibliothèque d'aide. On dit que la version 2.0 de Prototype.js subit des changements majeurs. Je ne sais pas s'il faut rompre avec l'historique, abandonner la compatibilité. , ou continuez à lutter pour survivre dans les fissures.

J'espère que cet article sera utile à la programmation jQuery de chacun.

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!