trouver un expert Python
Dans la partie 3 de cette série, vous avez ajouté des relations à l'API REST et à la base de données qui la prend en charge. Cela vous a donné un outil puissant que vous pouvez utiliser pour créer des programmes intéressants qui envoient des données persistantes, ainsi que les relations entre ces données, à un système de base de données. Avoir une API REST vous permet de créer une application à page unique (SPA) avec HTML, CSS et JavaScript. C’est un bon point de départ avant de faire le saut vers des frameworks frontaux plus puissants, tels que Angular ou React.
Dans cet article, vous apprendrez comment:
- Structurer un HTML fichier devant servir de modèle à une application Web d'une seule page
- Utiliser des feuilles de style en cascade (CSS) pour styliser la présentation d'une application
- Utiliser natif JavaScript ajouter de l'interactivité à une application
- Utilisez JavaScript pour adresser des requêtes HTTP AJAX à l'API REST que vous avez développée dans la troisième partie de cette série.
Vous pouvez obtenir tout le code que vous verrez dans ce tutoriel en cliquant sur le lien ci-dessous:
À qui s'adresse cet article
La première partie de cette série vous a guidé dans la construction d'une API REST et la deuxième partie vous a montré comment connecter cette API à une base de données. Dans la troisième partie, vous avez ajouté des relations à l'API REST et à la base de données prise en charge.
Cet article concerne la présentation de cette API REST à un utilisateur en tant qu'application Web basée sur un navigateur. Cette combinaison vous confère des compétences à la fois frontales et finales, un ensemble de compétences utiles et puissantes.
Création d'applications d'une seule page
Dans la partie 3 de cette série, vous avez ajouté des relations à l'API REST et à la base de données pour représenter les notes associées à des personnes. En d'autres termes, vous avez créé une sorte de mini-blog. Les applications Web que vous avez créées dans la partie 3 vous ont montré un moyen de présenter et d’interagir avec l’API REST. Vous avez navigué entre trois Applications mono-page (SPA) accéder à différentes parties de l’API REST.
Bien que vous ayez pu combiner cette fonctionnalité dans un seul SPA, cette approche rendrait les concepts de style et d’interactivité plus complexes, sans grande valeur ajoutée. Pour cette raison, chaque page était un SPA complet et autonome.
Dans cet article, vous allez vous concentrer sur Personnes SPA, qui présente la liste des personnes dans la base de données et fournit une fonctionnalité d’éditeur pour créer de nouvelles personnes et mettre à jour ou supprimer des personnes existantes. Les pages Accueil et Notes sont conceptuellement similaires.
Quels sont les cadres existants?
Il existe des bibliothèques offrant des fonctionnalités intégrées et robustes pour la création de systèmes SPA. Par exemple, la bibliothèque Bootstrap fournit un cadre populaire de styles permettant de créer des applications Web cohérentes et esthétiques. Il possède des extensions JavaScript qui ajoutent une interactivité aux éléments DOM stylés.
Il existe également de puissants frameworks d'applications Web, tels que React et Angular, qui vous offrent des systèmes complets de développement d'applications Web. Celles-ci sont utiles lorsque vous souhaitez créer de grands SPA de plusieurs pages qu'il serait difficile de créer à partir de zéro.
Pourquoi construire votre propre?
Avec la disponibilité d'outils comme ceux énumérés ci-dessus, pourquoi choisiriez-vous de créer un SPA à partir de rien? Prenez Bootstrap, par exemple. Vous pouvez l'utiliser pour créer des SPA qui ont une excellente apparence, et vous pouvez certainement l'utiliser avec votre code JavaScript!
Le problème est que Bootstrap a une courbe d’apprentissage abrupte que vous devrez gravir si vous voulez bien l’utiliser. Il ajoute également de nombreux attributs spécifiques à Bootstrap aux éléments DOM définis dans votre contenu HTML. De même, des outils tels que React et Angular ont également d’importantes courbes d’apprentissage que vous devrez surmonter. Cependant, il existe encore une place pour les applications Web qui ne reposent pas sur de tels outils.
Souvent, lorsque vous créez une application Web, vous souhaitez créer un preuve de concept d'abord pour voir si l'application est utile du tout. Vous voudrez que tout soit opérationnel rapidement afin que vous puissiez rouler votre propre prototype et le mettre à niveau ultérieurement. Etant donné que vous n'investirez pas beaucoup de temps dans le prototype, il ne sera pas trop coûteux de recommencer et de créer une nouvelle application avec un cadre complet pris en charge.
Il existe un écart entre ce que vous allez développer avec l’application Contacts dans cet article et ce que vous pourriez construire avec un cadre complet. C’est à vous de décider du point de basculement entre la fourniture de la fonctionnalité ou l’adoption d’un cadre.
Parties d'applications d'une page
Il existe quelques formes principales de l'interactivité dans les systèmes Web traditionnels. Vous pouvez naviguer entre les pages et soumettre une page avec de nouvelles informations. Vous pouvez remplir des formulaires contenant des champs de saisie, des boutons radio, des cases à cocher, etc. Lorsque vous effectuez ces activités, le serveur Web répond en envoyant de nouveaux fichiers à votre navigateur. Ensuite, votre navigateur restitue le contenu.
Les applications d'une seule page rompent ce modèle en chargeant tout ce dont elles ont besoin en premier. Ensuite, toute interaction ou navigation est gérée par JavaScript ou par des appels au serveur en coulisse. Ces activités mettent à jour le contenu de la page dynamiquement.
Une application d'une seule page comporte trois composants principaux:
- HTML fournit le contenu d'une page Web ou ce qui est rendu par votre navigateur.
- CSS fournit la présentation ou le style d'une page Web. Il définit à quoi le contenu de la page doit ressembler lorsqu'il est rendu par votre navigateur.
- JavaScript fournit l'interactivité d'une page Web. Il gère également la communication avec le serveur principal.
Ensuite, vous examinerez de plus près chacun de ces composants majeurs.
HTML
HTML est un fichier texte livré à votre navigateur qui fournit le principal contenu et structure pour une application d'une seule page. Cette structure inclut les définitions de identifiant
et classe
attributs, qui sont utilisés par CSS pour styliser le contenu et JavaScript pour interagir avec la structure. Votre navigateur analyse le fichier HTML pour créer le modèle DOM (Document Object Model), qu'il utilise pour rendre le contenu à l'affichage.
Le balisage dans un fichier HTML comprend Mots clés, comme les balises de paragraphe
...
et balises d'en-tête
...
. Ces balises deviennent des éléments dans le DOM lorsque votre navigateur analyse le code HTML et le restitue à l’affichage. Le fichier HTML contient également des liens vers des ressources externes que votre navigateur chargera lors de l'analyse du code HTML. Pour le SPA que vous construisez dans cet article, ces ressources externes sont des fichiers CSS et JavaScript.
CSS
Les feuilles de style en cascade (CSS) sont des fichiers contenant coiffant informations qui seront appliquées à toute structure DOM rendue à partir d'un fichier HTML. De cette manière, le contenu d'une page Web peut être séparé de sa présentation.
En CSS, le style d’une structure DOM est déterminé par sélecteurs. Un sélecteur est simplement une méthode permettant de faire correspondre un style à des éléments du DOM. Par exemple, le p
Le sélecteur dans le bloc de code ci-dessous applique les informations de style à tous les éléments de paragraphe:
p
poids de la police: audacieux;
Couleur de l'arrière plan: cyan;
Le style ci-dessus s'appliquera à tous les éléments de paragraphe du DOM. Le texte apparaîtra en gras et aura une couleur de fond cyan.
le en cascade partie de CSS signifie que les styles définis plus tard, ou dans un fichier CSS chargé après un autre, auront priorité sur tout style précédemment défini. Par exemple, vous pouvez définir un deuxième style de paragraphe après le style ci-dessus:
p
poids de la police: audacieux;
Couleur de l'arrière plan: cyan;
p
Couleur de l'arrière plan: bleuet;
Cette nouvelle définition de style modifierait le style existant afin que tous les éléments de paragraphe du DOM aient une couleur de fond de bleuet
. Ceci annule la Couleur de l'arrière plan
du style précédent, mais il laisse la poids de la police
cadre intact. Vous pouvez également définir le nouveau style de paragraphe dans un fichier CSS distinct.
le identifiant
et classe
Les attributs vous permettent d’appliquer un style à des éléments individuels spécifiques dans le DOM. Par exemple, le code HTML pour le rendu d'un nouveau DOM peut ressembler à ceci:
<p>
Ceci est un texte d'introduction
</p>
<p classe="panneau">
Ceci est du texte contenu dans un panneau
</p>
Cela créera deux éléments de paragraphe dans le DOM. Le premier n'a pas classe
attribut, mais le second a un classe
attribut de panneau
. Ensuite, vous pouvez créer un style CSS comme ceci:
p
poids de la police: audacieux;
largeur: 80%;
marge gauche: auto;
marge droite: auto;
Couleur de l'arrière plan: gris clair;
.panneau
frontière: 1px solide gris foncé;
rayon de la frontière: 4px;
rembourrage: dixpx;
Couleur de l'arrière plan: Lightskyblue;
Ici, vous définissez un style pour tous les éléments ayant le panneau
attribut. Lorsque votre navigateur rend le DOM, les deux éléments de paragraphe doivent ressembler à ceci:
La première définition de style est appliquée aux deux éléments de paragraphe, car p
sélecteur sélectionne les deux. Mais seul le deuxième paragraphe a la .panneau
style qui lui est appliqué car c’est le seul élément avec l’attribut class panneau
qui correspond à ce sélecteur. Le deuxième paragraphe contient de nouvelles informations de style de la part de .panneau
style, et remplace le Couleur de l'arrière plan
style défini dans le p
style.
JavaScript
JavaScript fournit toutes les fonctionnalités interactives d'un SPA, ainsi qu'une communication dynamique avec l'API REST fournie par le serveur. Il effectue également toutes les mises à jour du DOM, permettant ainsi à un SPA de se comporter comme une application à interface graphique complète, telle que Word ou Excel.
Au fur et à mesure de l'évolution de JavaScript, il est devenu plus facile et plus cohérent de travailler avec les DOM fournis par les navigateurs modernes. Vous utiliserez quelques conventions, telles que les espaces de noms et la séparation des problèmes, pour éviter que votre code JavaScript ne soit en conflit avec d’autres bibliothèques que vous pourriez inclure.
Remarque: Vous allez créer des applications d’une page en utilisant du JavaScript natif. En particulier, vous utiliserez la version ES2017, qui fonctionne avec de nombreux navigateurs modernes, mais peut poser problème si votre objectif est de prendre en charge les versions de navigateur plus anciennes.
Modules et espaces de noms
Vous connaissez peut-être déjà les espaces de noms en Python et leur valeur. En bref, espaces de noms vous donner un moyen de garder les noms dans votre programme unique pour éviter les conflits. Par exemple, si vous vouliez utiliser bûche()
à la fois le math
et cmath
modules, alors votre code pourrait ressembler à ceci:
>>> importation math
>>> importation cmath
>>> math.bûche(dix)
2.302585092994046
>>> cmath.bûche(dix)
(2.302585092994046 + 0j)
Le code Python ci-dessus importe à la fois le math
et cmath
modules, puis appelle log (10)
de chaque module. Le premier appel renvoie un nombre réel et le second renvoie un nombre complexe, qui cmath
a des fonctions pour. Chaque instance de bûche()
est unique dans son propre espace de noms (math
ou cmath
), signifiant les appels à bûche()
n'entre pas en conflit les uns avec les autres.
JavaScript moderne permet d'importer des modules et d'attribuer des espaces de noms à ces modules. Ceci est utile si vous devez importer d'autres bibliothèques JavaScript dans lesquelles il pourrait y avoir un conflit de noms.
Si vous regardez à la fin de la people.js
fichier, alors vous verrez ceci:
301 // Créer les composants MVC
302 const modèle = Nouveau Modèle();
303 const vue = Nouveau Vue();
304 const manette = Nouveau Manette(modèle, vue)
305
306 // Exporter les composants MVC par défaut
307 exportation défaut
308 modèle,
309 vue,
310 manette
311 ;
Le code ci-dessus crée les trois composants du système MVC, que vous verrez plus loin dans cet article. L'exportation par défaut du module est un objet littéral JavaScript. Vous importez ce module au bas de la personnes.html
fichier:
50 <scénario type="module">
51 // Donne un espace de nom aux composants MVC importés
52 importation * comme MVC de "/static/js/people.js";
53
54 // Créer une variable globale intentionnelle référençant l'importation
55 fenêtre.mvc = MVC;
56 </scénario>
Voici comment ce code fonctionne:
-
Ligne 50 les usages
type = "module"
pour indiquer au système que le fichier est un module et pas uniquement un fichier JavaScript. -
Ligne 52 importe l'objet par défaut de
people.js
et lui attribue le nomMVC
. Cela crée un espace de noms appeléMVC
. Vous pouvez attribuer à l'objet importé tout nom n'entrant pas en conflit avec d'autres bibliothèques JavaScript sur lesquelles vous n'avez peut-être pas le contrôle. -
Ligne 55 crée une variable globale, ce qui est une étape commode. Vous pouvez l'utiliser pour inspecter le
mvc
objet avec un débogueur JavaScript et regardermodèle
,vue
, etmanette
.
Remarque: Parce que MVC
est un module importé et pas seulement un fichier inclus, JavaScript passera par défaut en mode strict, ce qui présente certains avantages par rapport au mode non strict. L’un des plus importants est que vous ne pouvez pas utiliser de variables non définies.
Sans le mode strict activé, ceci est parfaitement légal:
var mon nom = "Salut";
myNane = "Bonjour le monde";
Voyez-vous l'erreur? La première ligne crée une variable appelée mon nom
et assigne la chaîne littérale "Salut"
à cela. La deuxième ligne regards comme il change le contenu de la variable à "Bonjour le monde"
mais ce n’est pas le cas!
En deuxième ligne, "Bonjour le monde"
est assigné au nom de la variable myNane
, qui est mal orthographié avec un n
. En JavaScript non strict, cela crée deux variables:
- La bonne variable
mon nom
- La version de frappe imprévue
myNane
Imaginez si ces deux lignes de code JavaScript étaient séparées par beaucoup d'autres. Cela pourrait créer un bug d’exécution difficile à trouver! Lorsque vous utilisez le mode strict, vous éliminez des erreurs comme celle-ci en générant une exception si votre code tente d'utiliser une variable non déclarée.
Conventions de nommage
Pour la plupart, le code JavaScript que vous utilisez ici est en camel. Cette convention de dénomination est largement utilisée dans la communauté JavaScript, donc les exemples de code reflètent cela. Cependant, votre code Python utilisera la casse de serpent, ce qui est plus conventionnel dans la communauté Python.
Cette différence de dénomination peut être source de confusion lorsque votre code JavaScript interagit avec le code Python, et particulièrement lorsque des variables partagées entrent dans l'interface de l'API REST. N'oubliez pas ces différences lorsque vous écrivez votre code.
Séparation des préoccupations
Le code qui conduit un SPA peut être compliqué. Vous pouvez utiliser le modèle d'architecture Modèle – Vue – Contrôleur (MVC) pour simplifier les choses en créant une séparation des problèmes. Les SPA Home, People et Notes utilisent le modèle MVC suivant:
-
Le modèle fournit tous les accès à l'API REST du serveur. Tout ce qui est présenté sur l’affichage provient du modèle. Toute modification des données passe par le modèle et retourne à l'API REST.
-
La vue contrôle tout le traitement de l'affichage et les mises à jour DOM. La vue est la seule partie du SPA qui interagit avec le DOM et force le navigateur à restituer et à restituer toute modification apportée à l'affichage.
-
Le controlle gère toutes les interactions utilisateur et toutes les données utilisateur entrées, comme les événements de clic. Étant donné que le contrôleur réagit aux entrées de l'utilisateur, il interagit également avec le modèle et la vue en fonction de cette entrée.
Voici une représentation visuelle du concept MVC tel qu’implémenté dans le code SPA:
Dans l'illustration ci-dessus, le contrôleur a un lien étroit avec le modèle et la vue. Encore une fois, cela est dû au fait que toute interaction utilisateur gérée par le contrôleur peut nécessiter un contact avec l'API REST pour obtenir ou mettre à jour des données. Cela peut même nécessiter une mise à jour de l'affichage.
La ligne en pointillé qui va du modèle au contrôleur indique une connexion faible. Les appels à l'API REST étant asynchrones, les données que le modèle fournit au contrôleur sont renvoyées ultérieurement.
Créer le SPA des personnes
Votre application de démonstration de mini-blog contient des pages pour Accueil, Personnes et Notes. Chacune de ces pages est un SPA complet et autonome. Ils utilisent tous la même conception et la même structure. Par conséquent, même si vous vous concentrez sur l’application Contacts, vous comprendrez comment les construire.
Personnes HTML
L'infrastructure Web Python Flask fournit le moteur de création de modèles Jinja2, que vous utiliserez pour People SPA. Certaines parties du SPA sont communes aux trois pages. Chaque page utilise donc le Jinja2. héritage de modèle fonction pour partager ces éléments communs.
Le contenu HTML du People SPA est fourni dans deux fichiers: parent.html
et people.html
des dossiers. Vous pouvez obtenir le code de ces fichiers en cliquant sur le lien ci-dessous:
Voici ce que votre parent.html
ressemblera:
1
2 <html lang="fr">
3 <tête>
4 <méta jeu de caractères="UTF-8">
5 % block head%
6 <Titre>% block title% % endblock% Page</Titre>
sept % endblock%
8 </tête>
9 <corps>
dix <div classe="la navigation">
11 <envergure classe="boutons">
12 <une href="/">Accueil</une>
13 <une href="/personnes">Personnes</une>
14 </envergure>
15 <envergure classe="Nom de la page">
16 <div> </div>
17 </envergure>
18 <envergure classe="spacer"> </envergure>
19 </div>
20
21 % block body%
22 % endblock%
23 </corps>
24
25 % block javascript%
26 % endblock%
27
28 </html>
parent.html
a quelques éléments majeurs:
- Ligne 1 définit le type de document comme
. Toutes les nouvelles pages HTML commencent par cette déclaration. Les navigateurs modernes savent que cela signifie utiliser le standard HTML 5, tandis que les navigateurs plus anciens retomberont sur le dernier standard qu’ils peuvent prendre en charge.
- Ligne 4 indique au navigateur d’utiliser le codage UTF-8.
- Lignes 10 à 19 définir la barre de navigation.
- Lignes 21 et 22 sont des marqueurs de bloc Jinja2, qui seront remplacés par le contenu de
people.html
. - Lignes 25 et 26 sont des marqueurs de bloc Jinja2 qui agissent comme un espace réservé pour le code JavaScript.
le people.html
le fichier héritera du parent.html
code. Vous pouvez développer le bloc de code ci-dessous pour voir le fichier entier:
1 % extend "parent.html"%
2 % block title% People % endblock%
3 % block head%
4 % endblock%
5 % block page_name% Personne créer / mettre à jour / supprimer une page % endblock%
6
sept % block body%
8 <div classe="récipient">
9 <contribution identifiant="url_person_id" type="caché" valeur="person_id" />
dix <div classe="éditeur de section">
11 <div>
12 <envergure>Identifiant de la personne:</envergure>
13 <envergure identifiant="person_id"> </envergure>
14 </div>
15 <étiquette pour="fname">Prénom
16 <contribution identifiant="fname" type="texte" />
17 </étiquette>
18 <br />
19 <étiquette pour="lname">Nom de famille
20 <contribution identifiant="lname" type="texte" />
21 </étiquette>
22 <br />
23 <bouton identifiant="créer">Créer</bouton>
24 <bouton identifiant="mise à jour">Mise à jour</bouton>
25 <bouton identifiant="effacer">Effacer</bouton>
26 <bouton identifiant="réinitialiser">Réinitialiser</bouton>
27 </div>
28 <div classe="personnes">
29 <table>
30 <légende>Personnes</légende>
31 <la tête>
32 <tr>
33 <th>Horodatage de création / mise à jour</th>
34 <th>La personne</th>
35 </tr>
36 </la tête>
37 </table>
38 </div>
39 <div classe="Erreur">
40 </div>
41 </div>
42 <div classe="Erreur">
43 </div>
44
45 % endblock%
people.html
a juste deux différences majeures:
- Ligne 1 indique à Jinja2 que ce modèle hérite de la
parent.html
modèle. - Lignes 7 à 45 créer le corps de la page. Cela inclut la section d'édition et un tableau vide pour présenter la liste des personnes. Ceci est le contenu inséré dans le
% block body% % endblock%
section de laparent.html
fichier.
La page HTML générée par parent.html
et people.html
ne contient aucune information de style. Au lieu de cela, la page est rendue dans le style par défaut du navigateur que vous utilisez pour la visualiser. Voici à quoi ressemble votre application lorsqu'elle est rendue par le navigateur Chrome:
Cela ne ressemble pas beaucoup à une application à une seule page! Voyons ce que vous pouvez faire à ce sujet.
Gens CSS
Pour styliser le People SPA, vous devez d’abord ajouter le normaliser.css
feuille de style. Cela garantira que tous les navigateurs rendent systématiquement les éléments plus proches des normes HTML 5. Le CSS spécifique pour People SPA est fourni par deux feuilles de style:
parent.css
avec lequel vous arrivezparent.html
people.css
avec lequel vous arrivezpeople.html
Vous pouvez obtenir le code de ces feuilles de style en cliquant sur le lien ci-dessous:
Vous allez ajouter les deux normaliser.css
et parent.css
à la ...
section de parent.html
:
1 <tête>
2 <méta jeu de caractères="UTF-8">
3 % block head%
4 <Titre>% block title% % endblock% Page</Titre>
5 <lien rel="feuille de style" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css">
6 <lien rel="feuille de style" href="/static/css/parent.css">
sept % endblock%
8 </tête>
Voici ce que font ces nouvelles lignes:
- Ligne 5 obtient
normaliser.css
depuis un réseau de diffusion de contenu (CDN), vous n’avez donc pas à le télécharger vous-même. - Ligne 6 obtient
parent.css
depuis votre applicationstatique
dossier.
Pour la plupart, parent.css
définit les styles pour les éléments de navigation et d'erreur. Il remplace également la police par défaut par la police Roboto de Google à l’aide des lignes suivantes:
5 @importation url(http: //les polices.googleapis.com/css?famille=Roboto:400,300,500,700);
6
sept corps, .ui-btn
8 famille de polices: Roboto;
9
Vous extrayez la police Roboto à partir d'un CDN Google. Ensuite, vous appliquez cette police à tous les éléments du corps du SPA qui possèdent également une classe de .ui-btn
.
Également, people.css
contient des informations de style spécifiques aux éléments HTML qui créent le People SPA. Vous ajoutez people.css
à la people.html
déposer à l'intérieur du Jinja2 % block head%
section:
3 % block head%
4 super ()
5 <lien rel="feuille de style" href="/static/css/people.css">
6 % endblock%
Le fichier contient quelques nouvelles lignes:
- Ligne 2 a un appel à super (). Ceci dit à Jinja2 d’inclure tout ce qui existe dans le
% block head%
section deparent.html
. - Ligne 3 tire dans le
people.css
fichier à partir du dossier statique de votre application.
Une fois les feuilles de style incluses, votre People SPA ressemblera davantage à ceci:
Le People SPA a l'air mieux, mais il est encore incomplet. Où sont les lignes de données de personnes dans la table? Tous les boutons de la section éditeur sont activés, alors pourquoi ne font-ils rien? Vous corrigerez ces problèmes dans la section suivante avec du JavaScript.
Personnes JavaScript
Vous allez extraire des fichiers JavaScript dans People SPA comme vous l’avez fait pour les fichiers CSS. Vous allez ajouter le bit de code suivant au bas de people.html
fichier:
48 % block javascript%
49 super ()
50 <scénario type="module">
51 // Donne un espace de nom aux composants MVC importés
52 importation * comme MVC de "/static/js/people.js";
53
54 // Créer une variable globale intentionnelle référençant l'importation
55 fenêtre.mvc = MVC;
56 </scénario>
57 % endblock%
Remarquez le type = "module"
déclaration sur l'ouverture balise à la ligne 50. Cela indique au système que le script est un module JavaScript. L'ES6
importation
La syntaxe sera utilisée pour extraire les parties exportées du code dans le contexte du navigateur.
Le peuple MVC
Toutes les pages SPA utilisent une variante du modèle MVC. Voici un exemple d’implémentation en JavaScript:
1 // Créer les composants MVC
2 const modèle = Nouveau Modèle();
3 const vue = Nouveau Vue();
4 const manette = Nouveau Manette(modèle, vue)
5
6 // Exporter les composants MVC par défaut
sept exportation défaut
8 modèle,
9 vue,
dix manette
11 ;
Ce code ne fait rien pour l'instant, mais vous pouvez l'utiliser pour voir les éléments suivants de la structure et de la mise en œuvre de MVC:
- Ligne 2 crée une instance de la classe Model et l'assigne à
modèle
. - Ligne 3 crée une instance de la classe View et l'assigne à
vue
. - Ligne 4 crée une instance de la classe Controller et l'assigne à
manette
. Notez que vous passez les deuxmodèle
etvue
au constructeur. Voici comment le contrôleur obtient un lien vers lemodèle
etvue
variables d'instance. - Lignes 7 à 11 exporter un objet littéral JavaScript en tant qu'exportation par défaut.
Parce que tu rentres people.js
en bas de people.html
, le JavaScript est exécuté après votre navigateur crée les éléments SPA DOM. Cela signifie que JavaScript peut accéder en toute sécurité aux éléments de la page et commencer à interagir avec le DOM.
Encore une fois, le code ci-dessus ne fait rien pour l'instant. Pour que cela fonctionne, vous devez définir votre modèle, vue et contrôleur.
Modèle de personnes
le Modèle est responsable de la communication avec l'API REST fournie par le serveur Flask. Toutes les données provenant de la base de données, ainsi que les données modifiées ou créées par le SPA, doivent passer par le modèle. Toutes les communications avec l'API REST sont effectuées à l'aide d'appels HTTP AJAX initiés par JavaScript.
JavaScript moderne fournit chercher ()
, que vous pouvez utiliser pour passer des appels AJAX. Le code de votre classe Model implémente une méthode AJAX pour lire le point de terminaison URL de l'API REST. / api / personnes
et obtenir toutes les personnes dans la base de données:
1 classe Modèle
2 async lis()
3 laisser Les options =
4 méthode: "OBTENIR",
5 cache: "no-cache",
6 en-têtes:
sept "Type de contenu": "application / json"
8 "accepte": "application / json"
9
dix ;
11 // Appelez le noeud final REST et attendez les données.
12 laisser réponse = attendre aller chercher(`/ api / people`, Les options)
13 laisser Les données = attendre réponse.JSON();
14 revenir Les données;
15
16
Voici comment ce code fonctionne:
-
Ligne 1 définit la classe
Modèle
. C’est ce qui sera exporté plus tard dans le cadre dumvc
objet. -
Ligne 2 commence la définition d'une méthode asynchrone appelée
lis()
. leasync
mot-clé devantlis()
indique à JavaScript que cette méthode effectue un travail asynchrone. -
Lignes 3 à 9 créé un
Les options
objet avec des paramètres pour l'appel HTTP, comme la méthode et les attentes de l'appel pour les données. -
Ligne 12 les usages
chercher ()
faire un appel HTTP asynchrone à la/ api / personnes
Point de terminaison d'URL fourni par le serveur. Le mot cléattendre
devant dechercher ()
indique à JavaScript d'attendre de manière asynchrone la fin de l'appel. Lorsque cela est terminé, les résultats sont affectés àréponse
. -
Ligne 13 convertit de manière asynchrone la chaîne JSON dans la réponse à un objet JavaScript et l'assigne à
Les données
. -
Ligne 14 renvoie les données à l'appelant.
Pour l’essentiel, ce code indique à JavaScript de faire un OBTENIR
Demande HTTP à / api / personnes
, et que l'appelant attend un Type de contenu
de application / json
et JSON
Les données. Rappelons qu'un OBTENIR
Un appel HTTP équivaut à Lis
dans un système orienté CRUD.
Basé sur la configuration de Connexion définie dans swagger.yml
, cet appel HTTP appellera def read_all ()
. Cette fonction est définie dans people.py
et interroge la base de données SQLite pour créer une liste de personnes à renvoyer à l'appelant. Vous pouvez obtenir le code de tous ces fichiers en cliquant sur le lien ci-dessous:
Dans le navigateur, JavaScript s'exécute dans un seul thread et est conçu pour répondre aux actions de l'utilisateur. De ce fait, c’est une mauvaise idée de bloquer l’exécution de JavaScript qui attend que quelque chose s’achève, comme une requête HTTP adressée à un serveur.
Que se passe-t-il si la requête est envoyée sur un réseau très lent ou si le serveur est en panne et ne répond jamais? Si JavaScript devait bloquer et attendre la fin de la requête HTTP dans ce type de conditions, il pourrait alors s'achever en quelques secondes, quelques minutes, voire pas du tout. Bien que JavaScript soit bloqué, rien d'autre dans le navigateur ne réagirait aux actions de l'utilisateur!
Pour empêcher ce comportement de blocage, les requêtes HTTP sont exécutées asynchrone. Cela signifie qu'une requête HTTP retourne à la boucle d'événements immédiatement avant la fin de la requête. le boucle d'événement existe dans toute application JavaScript exécutée dans le navigateur. La boucle attend en permanence la fin d'un événement pour pouvoir exécuter le code associé à cet événement.
Quand vous placez le attendre
mot clé avant chercher ()
, vous indiquez à la boucle d'événements où retourner lorsque la requête HTTP est terminée. À ce stade, la demande est terminée et les données renvoyées par l'appel sont attribuées à réponse
. Ensuite, manette
appels this.model.read ()
recevoir les données retournées par la méthode. Cela crée un lien faible avec le manette
comme le modèle
ne sait rien de ce qui l’a appelé, mais de ce qui est retourné à cet appelant.
People View
cette vue
est responsable de l'interaction avec le DOM, ce qui est indiqué par l'affichage. Il peut modifier, ajouter et supprimer des éléments du DOM, qui sont ensuite restitués à l'affichage. le manette
appelle les méthodes de la vue pour mettre à jour l’affichage. le Vue
est une autre classe JavaScript avec les méthodes que le contrôleur peut appeler.
Vous trouverez ci-dessous une version légèrement simplifiée de la Vue
classe:
1 classe Vue
2 constructeur()
3 cette.table = document.querySelector("table de personnes")
4 cette.person_id = document.getElementById("person_id")
5 cette.fname = document.getElementById("fname")
6 cette.lname = document.getElementById("lname")
sept
8
9 réinitialiser()
dix cette.person_id.textContent = "";
11 cette.lname.valeur = "";
12 cette.fname.valeur = "";
13 cette.fname.concentrer();
14
15
16 buildTable(personnes)
17 laisser tbody,
18 html = "";
19
20 // Itère sur le peuple et construit la table
21 personnes.pour chaque((la personne) =>
22 html + = `
23 <tr data-person_id = "$ la personne.person_id"data-fname ="$ la personne.fname"data-lname ="$ la personne.lname">
24 $ la personne.horodatage
25 $ la personne.fname $ la personne.lname
26 `;
27 );
28 // Y a-t-il actuellement un tbody dans la table?
29 si (cette.table.tBodies.longueur ! == 0)
30 cette.table.enleverChild(cette.table.getElementsByTagName("tbody")[[[[0])
31
32 // Mettre à jour tbody avec notre nouveau contenu
33 tbody = cette.table.createTBody();
34 tbody.innerHTML = html;
35
36
Voici comment ce code fonctionne:
-
Ligne 1 commence la définition de la classe.
-
Lignes 2 à 7 définir le constructeur de la classe, un peu comme le
def __init __ (auto):
définition dans une classe Python. Le constructeur récupère des éléments du DOM et crée des variables d'alias à utiliser dans d'autres parties de la classe. lecette.
en face de ces noms de variables est un peu commesoi.
en Python. Il désigne l'instance actuelle de la classe lorsqu'elle est utilisée. -
Lignes 9 à 14 définir
réinitialiser()
, que vous utiliserez pour rétablir le statut par défaut de la page. -
Lignes 16 à 36 définir
buildTable ()
, qui construit la table des personnes basée sur lapersonnes
les données qui lui sont transmises.
Les variables d’alias sont créées pour mettre en cache les objets DOM renvoyés par les appels à document.getElementByID ()
et document.querySelector ()
, qui sont des opérations JavaScript relativement coûteuses. Cela permet une utilisation rapide des variables dans les autres méthodes de la classe.
Regardons de plus près build_table ()
, qui est la deuxième méthode de la Vue
classe:
16 buildTable(personnes)
17 laisser tbody,
18 html = "";
19
20 // Itère sur le peuple et construit la table
21 personnes.pour chaque((la personne) =>
22 html + = `
23 <tr data-person_id = "$ la personne.person_id"data-fname ="$ la personne.fname"data-lname ="$ la personne.lname">
24 $ la personne.horodatage
25 $ la personne.fname $ la personne.lname
26 `;
27 );
28 // Y a-t-il actuellement un tbody dans la table?
29 si (cette.table.tBodies.longueur ! == 0)
30 cette.table.enleverChild(cette.table.getElementsByTagName("tbody")[[[[0])
31
32 // Mettre à jour tbody avec notre nouveau contenu
33 tbody = cette.table.createTBody();
34 tbody.innerHTML = html;
35
Voici comment fonctionne la fonction:
- Ligne 16 crée la méthode et passe le
personnes
variable en paramètre. - Lignes 21 à 27 itérer sur le
personnes
données en utilisant des fonctions de flèche JavaScript pour créer une fonction qui construit les lignes de la table dans lehtml
variable. - Lines 29 to 31 remove any
elements in the table if they exist.- Line 33 creates a new
tbody
element in the table.- Line 34 inserts the
html
string previously created into thetbody
element as HTML.This function dynamically builds the table in the People SPA from the data passed to it, which is the list of people that came from the
/api/people/
REST API call. This data is used along with JavaScript template strings to generate the table rows to insert into the table.People Controller
le Controller is the central clearinghouse of the MVC implementation, as it coordinates the activity of both
model
etvue
. As such, the code to define it is a little more complicated. Here’s a simplified version:1 class Controller { 2 constructor(model, vue) 3 cette.model = model; 4 cette.vue = vue; 5 6 cette.initialize(); sept 8 async initialize() 9 await cette.initializeTable(); dix 11 async initializeTable() 12 try 13 let urlPersonId = parseInt(document.getElementById("url_person_id").value), 14 people = await cette.model.read(); 15 16 cette.vue.buildTable(people) 17 18 // Did we navigate here with a person selected? 19 if (urlPersonId) 20 let person = await cette.model.readOne(urlPersonId) 21 cette.vue.updateEditor(person) 22 cette.vue.setButtonState(cette.vue.EXISTING_NOTE) 23 24 // Otherwise, nope, so leave the editor blank 25 else 26 cette.vue.reset(); 27 cette.vue.setButtonState(cette.vue.NEW_NOTE) 28 29 cette.initializeTableEvents(); 30 catch (err) 31 cette.vue.errorMessage(err) 32 33 34 initializeCreateEvent() 35 document.getElementById("create").addEventListener("click", async (evt) => 36 let fname = document.getElementById("fname").value, 37 lname = document.getElementById("lname").value; 38 39 evt.preventDefault(); 40 try 41 await cette.model.create( 42 fname: fname, 43 lname: lname 44 ); 45 await cette.initializeTable(); 46 catch(err) 47 cette.vue.errorMessage(err) 48 49 ); 50 51 }
Here’s how it works:
-
Line 1 begins the definition of the Controller class.
-
Lines 2 to 7 define the class constructor and create the instance variables
this.model
etthis.view
with their respective parameters. It also callsthis.initialize()
to set up the event handling and build the initial table of people. -
Lines 8 to 10 define
initialize()
and mark it as an asynchronous method. It callsthis.initializeTable()
asynchronously and waits for it to complete. This simplified version only includes this one call, but the full version of the code contains other initialization methods used for the rest of the event handling set up. -
Line 11 defines
initializeTable()
as an asynchronous method. This is necessary because it callsmodel.read()
, which is also asynchronous. -
Line 13 declares and initializes the
urlPersonId
variable with the value of the HTML hidden inputurl_person_id
. -
Line 14 calls
this.model.read()
and asynchronously waits for it to return with people data. -
Line 16 calls
this.view.buildTable(people)
to fill the HTML table with people data. -
Lines 19 to 28 determine how to update the editor portion of the page.
-
Line 29 calls
this.initializeTableEvents()
to install the event handling for the HTML table. -
Line 31 calls
this.view.errorMessage(err)
to display errors should they occur. -
Lines 34 to 49 install a click event handler on the create button. This calls
this.model.create(...)
to create a new person using the REST API, and updates the HTML table with new data.
The bulk of the
controller
code is like this, setting event handlers for all the expected events on the People SPA page. The controller continues creating functions in those event handlers to orchestrate calls tothis.model
etthis.view
, so that they perform the right actions when those events occur.When your code is complete, your People SPA page will look like this:
The content, styling, and functionality are all complete!
Conclusion
You’ve covered a great deal of new ground and should be proud of what you’ve learned! It can be tricky to jump back and forth between Python and JavaScript to create a complete Single-Page Application.
If you keep your contenu (HTML), presentation (CSS), and interaction (JavaScript) separate, then you can substantially reduce the complexity. You can also make JavaScript coding more manageable by using the MVC pattern to further break down the complexity of user interaction.
You’ve seen how using these tools and ideas can help you create reasonably complex Single-Page Applications. Now you’re better equipped to make decisions about whether to build an app this way, or take the plunge into a larger framework!
You can get all of the code you saw in this tutorial at the link below:
[ad_2]
Iconic One Theme | Powered by Wordpress - Line 33 creates a new