Maison > interface Web > js tutoriel > Penser dans les composants

Penser dans les composants

Joseph Gordon-Levitt
Libérer: 2025-02-21 09:54:16
original
153 Les gens l'ont consulté

Penser dans les composants

Les plats clés

  • L'approche des composants du développement d'interface offre des avantages sur les cadres traditionnels MVC et MVVM, en se concentrant sur les plus petites sections abstraites d'interaction plutôt que sur la modélisation des domaines commerciaux.
  • Les composants
  • doivent être conçus pour être réutilisés, éloignés du domaine commercial et adaptables à différents contextes. Cette approche peut être illustrée dans la création d'un composant d'entrée de texte suggestif qui peut être utilisé universellement, plutôt qu'un composant de recherche d'aide de type spécifique.
  • La rupture des interfaces en composants composables simplifie non seulement le processus de développement, mais facilite également les tests isolés. Les composants sont indépendants les uns des autres, permettant des modifications et des ajouts sans interférer avec le système global.

Composants Web, React, Polymer, Flight - Tous sont destinés à construire des composants d'interface. Il s'agit d'un ensemble d'outils différent des frameworks Big MVC et MVVM, et nécessite un état d'esprit différent lors de la planification de la façon dont vous allez implémenter votre interface. Bien que j'utilise toujours des modèles comme MVC pour les applications de serveur, je suis un converti dédié aux avantages d'une approche composante pour le développement d'interface. Dans cet article, je vais décrire comment la pensée dans les composants diffère de la pensée dans MVC et implémenter cette approche dans un exemple réel.

Dans mon esprit, l'espace de tête de MVC Design est «Comment modéliser mon domaine commercial? Comment modéliser les processus d'interaction avec ce domaine? Comment modéliser l'interface pour faciliter ces processus? ». Je pense que cet espace de tête ne facilite pas la conception de bons composants. En fait, c'est l'opposé polaire pour savoir comment vous devriez penser lorsque vous avez décidé de décomposer une interface en composants composables. Au mieux, vous vous retrouverez avec des micro applications. Au pire, vous construirez des composants de Dieu. La dernière chose que vous voulez faire est de modéliser votre domaine commercial en tant que composants. Ce que vous devez viser à modéliser, ce sont les plus petites sections abstraites d'interaction que vous pouvez décrire.

Conception pour réutiliser

Au lieu de «Comment faire ce panneau d'alerte licenciable?» Je trouve que cela conduit à des composants qui sont en toute sécurité éloignés du domaine commercial et intrinsèquement les plus réutilisables dans différents contextes.

Comme autre exemple, ne faites pas un composant de recherche d'aide de type qui est utilisé partout où vous souhaitez permettre la recherche du système d'aide, faites un composant d'entrée de texte suggestif qui connaît les interactions impliquées dans la fourniture de suggestions d'entrée. Ensuite, faites un composant de données API de recherche d'aide qui sait comment recevoir des demandes de données, interagir avec l'API de recherche d'aide et diffuser les résultats. Maintenant, les tests de votre entrée de texte suggestifs n'ont pas besoin de moquerie des API, et lorsque vous êtes invité à ajouter des suggestions à un champ «tag», vous pouvez déposer votre composant d'entrée de texte suggestif existant, câbler un composant de données simple qui parle à l'API Tag, et fait!

Exemple pratique - «Liste des projets»

Pour un exemple concret, jetons un coup d'œil à l'implémentation d'une interface simple en tant que composants isolés. La maquette suivante est une extraction du système de projets de 1 à 1 de la conception de 99. Bien que l'interface utilisateur ait été radicalement simplifiée, le JavaScript que nous allons construire est le code de production de notre site au moment de la rédaction. Voici le wireframe:

Penser dans les composants

Ce que nous avons, c'est la navigation entre trois listes de projets - actifs, brouillons et archivés. Chaque projet a une action qui peut être effectuée sur elle - archiver un projet actif, supprimer un projet ou réactiver un projet archivé. Dans la conception d'applications, pensant que nous commencerions à modéliser un projet et à lui donner des méthodes comme «Archive» et «Delete», et une propriété «statut» pour suivre les trois listes dans lesquelles il appartient. Amener cette ligne de raisonnement à la conception des composants est Exactement ce que nous voulons éviter, nous allons donc nous préoccuper uniquement des interactions et de ce qui est nécessaire pour les faciliter.

Au cœur de celui-ci, nous avons une action par ligne. Lorsque cette action est effectuée, nous voulons supprimer la ligne de la liste. Nous avons déjà perdu toute connaissance du domaine spécifique au projet! De plus, nous avons un compte avec le nombre d'éléments dans chaque liste. Pour restreindre la portée de cet article, nous supposons que chaque page est générée côté serveur, la navigation à l'onglet provoquant un actualisation pleine page. Comme nous n'avons pas besoin de forcer la dépendance à JavaScript, nos boutons d'action seront des éléments de formulaire avec des gestionnaires d'événements de soumettre qui effectueront de manière asynchrone l'action du formulaire et diffuseront un événement lorsqu'il sera terminé.

voici quelques HTML pour une seule ligne de projet:

<span><span><span><li</span>></span>
</span>  <span><span><span><a</span> href<span>="/projects/99"</span> title<span>="View project"</span>></span>Need sticker designs for XYZ Co.<span><span></a</span>></span>
</span>  <span><span><span><div</span> class<span>="project__actions"</span>></span>
</span>    <span><span><span><a</span> href<span>="/projects/99"</span> class<span>="button"</span>></span>View<span><span></a</span>></span>
</span>    <span><span><span><form</span> class<span>="action"</span> action<span>="/projects/99/archive"</span> method<span>="post"</span>></span>
</span>        <span><span><span><button</span>></span>Archive<span><span></button</span>></span>
</span>    <span><span><span></form</span>></span>
</span>  <span><span><span></div</span>></span>
</span><span><span><span></li</span>></span></span>
Copier après la connexion
Copier après la connexion

J'utiliserai Flight pour construire nos composants. Le vol est actuellement notre bibliothèque de composants JS par défaut à 99Designs pour les raisons que j'ai décrites dans mon précédent article JavaScript SitePoint.

Voici notre composant AsyncForm pour gérer la soumission du formulaire et diffuser un événement:

<span>define(function(require) {
</span>  <span>'use strict';
</span>
  <span>var defineComponent = require('flight/lib/component');
</span>
  <span>function <span>AsyncForm</span>() {
</span>    <span>this.defaultAttrs({
</span>      <span>broadcastEvent: 'uiFormProcessed'
</span>    <span>});
</span>
    <span>this.after('initialize', function() {
</span>      <span>this.on(this.node, 'submit', this.asyncSubmit.bind(this));
</span>    <span>});
</span>
    <span>this.asyncSubmit = function(event) {
</span>      event<span>.preventDefault();
</span>      $<span>.ajax({
</span>        <span>'url': this.$node.attr('action'),
</span>        <span>'dataType': 'json',
</span>        <span>'data': this.$node.serializeArray(),
</span>        <span>'type': this.$node.attr('method')
</span>      <span>}).done(function(response<span>, data</span>) {
</span>        <span>this.$node.trigger(this.attr.broadcastEvent, data);
</span>      <span>}.bind(this)).fail(function() {
</span>        <span>// error handling excluded for brevity
</span>      <span>});
</span>    <span>};
</span>  <span>}
</span>
  <span>return defineComponent(AsyncForm);
</span><span>});</span>
Copier après la connexion
Copier après la connexion

Nous maintenons une stratégie stricte de ne jamais utiliser d'attributs de classe pour JavaScript, nous allons donc ajouter un attribut de forme de données-async à nos formulaires d'action, et attacher nos composants à tous les formulaires correspondants comme SO:

<span><span><span><li</span>></span>
</span>  <span><span><span><a</span> href<span>="/projects/99"</span> title<span>="View project"</span>></span>Need sticker designs for XYZ Co.<span><span></a</span>></span>
</span>  <span><span><span><div</span> class<span>="project__actions"</span>></span>
</span>    <span><span><span><a</span> href<span>="/projects/99"</span> class<span>="button"</span>></span>View<span><span></a</span>></span>
</span>    <span><span><span><form</span> class<span>="action"</span> action<span>="/projects/99/archive"</span> method<span>="post"</span>></span>
</span>        <span><span><span><button</span>></span>Archive<span><span></button</span>></span>
</span>    <span><span><span></form</span>></span>
</span>  <span><span><span></div</span>></span>
</span><span><span><span></li</span>></span></span>
Copier après la connexion
Copier après la connexion

Maintenant, nous avons la possibilité d'effectuer l'action et diffuser un événement qui propagera l'arbre Dom sur le succès. L'étape suivante consiste à écouter cet événement et à retirer la ligne qu'elle bouillonne. Pour cela, nous avons amovible:

<span>define(function(require) {
</span>  <span>'use strict';
</span>
  <span>var defineComponent = require('flight/lib/component');
</span>
  <span>function <span>AsyncForm</span>() {
</span>    <span>this.defaultAttrs({
</span>      <span>broadcastEvent: 'uiFormProcessed'
</span>    <span>});
</span>
    <span>this.after('initialize', function() {
</span>      <span>this.on(this.node, 'submit', this.asyncSubmit.bind(this));
</span>    <span>});
</span>
    <span>this.asyncSubmit = function(event) {
</span>      event<span>.preventDefault();
</span>      $<span>.ajax({
</span>        <span>'url': this.$node.attr('action'),
</span>        <span>'dataType': 'json',
</span>        <span>'data': this.$node.serializeArray(),
</span>        <span>'type': this.$node.attr('method')
</span>      <span>}).done(function(response<span>, data</span>) {
</span>        <span>this.$node.trigger(this.attr.broadcastEvent, data);
</span>      <span>}.bind(this)).fail(function() {
</span>        <span>// error handling excluded for brevity
</span>      <span>});
</span>    <span>};
</span>  <span>}
</span>
  <span>return defineComponent(AsyncForm);
</span><span>});</span>
Copier après la connexion
Copier après la connexion

De nouveau, nous ajoutons un attribut amovible de données à nos lignes de projet et attachons le composant aux éléments de ligne:

<span>AsyncForm.attachTo('[data-async-form]');</span>
Copier après la connexion

fait! Deux petits composants avec un événement chacun, et nous avons géré les trois types d'actions dans nos trois formes d'une manière qui se dégrade gracieusement. Il ne reste plus qu'une chose, et c'est notre compte sur chaque onglet. Devrait être assez facile, tout ce dont nous avons besoin est de décrémenter le nombre de l'onglet actif à chaque fois qu'une ligne est supprimée. Mais attendez! Lorsqu'un projet actif est archivé, le nombre d'archives doit augmenter et lorsqu'un projet archivé est réactivé, le nombre activé doit augmenter. Permet d'abord de faire un composant de comptage qui peut recevoir des instructions pour modifier son numéro:

<span>define(function(require) {
</span>  <span>'use strict';
</span>
  <span>var defineComponent = require('flight/lib/component');
</span>
  <span>function <span>Removable</span>() {
</span>    <span>this.defaultAttrs({
</span>      <span>'removeOn': 'uiFormProcessed'
</span>    <span>});
</span>
    <span>this.after('initialize', function() {
</span>      <span>this.on(this.attr.removeOn, this.remove.bind(this));
</span>    <span>});
</span>
    <span>this.remove = function(event) {
</span>      <span>// Animate row removal, remove DOM node, teardown component
</span>      $<span>.when(this.$node
</span>        <span>.animate({'opacity': 0}, 'fast')
</span>        <span>.slideUp('fast')
</span>      <span>).done(function() {
</span>        <span>this.$node.remove();
</span>      <span>}.bind(this));
</span>    <span>};
</span>  <span>}
</span>
  <span>return defineComponent(Removable);
</span><span>});</span>
Copier après la connexion

Notre nombre serait représenté dans HTML comme quelque chose comme 4 . Parce que le nombre écoute les événements au niveau du document, nous rendrons sa propriété d'événement NULL. Cela en obligera toute utilisation pour définir un événement que cette instance devrait écouter et empêcher accidentellement des instances de comptage multiples à écouter des instructions sur le même événement.

<span>Removable.attachTo('[data-removable]');</span>
Copier après la connexion

La dernière pièce du puzzle consiste à obtenir nos instances amovibles pour licencier un événement avec un modificateur de leurs comptoirs respectifs lorsqu'ils sont supprimés. Nous ne voulons certainement pas de couplage entre les composants, donc nous donnerons un attribut amovible qui est un éventail d'événements à tirer quand il est supprimé:

<span>define(function(require) {
</span>  <span>'use strict';
</span>
  <span>var defineComponent = require('flight/lib/component');
</span>
  <span>function <span>Count</span>() {
</span>    <span>this.defaultAttrs({
</span>      <span>'event': null
</span>    <span>});
</span>
    <span>this.after('initialize', function() {
</span>      <span>this.on(document, this.attr.event, this.update.bind(this));
</span>    <span>});
</span>
    <span>this.update = function(event<span>, data</span>) {
</span>      <span>this.$node.text(
</span>        <span>parseInt(this.$node.text(), 10) + data.modifier
</span>      <span>);
</span>    <span>}
</span>  <span>}
</span>
  <span>return defineComponent(Count);
</span><span>});</span>
Copier après la connexion

Maintenant, le couplage entre le décompte et la amovible se produit dans le script de page spécifique au cas d'utilisation où nous attachons nos composants au DOM:

<span>Count.attachTo(
</span>  <span>'[data-counter="active"]',
</span>  <span>{'event': 'uiActiveCountChanged'}
</span><span>);
</span>
<span>Count.attachTo(
</span>  <span>'[data-counter="draft"]',
</span>  <span>{'event': 'uiDraftCountChanged'}
</span><span>);
</span>
<span>Count.attachTo(
</span>  <span>'[data-counter="archived"]',
</span>  <span>{'event': 'uiArchivedCountChanged'}
</span><span>);</span>
Copier après la connexion

Mission accomplie. Nos compteurs ne savent rien de nos lignes de liste de projets, qui ne savent rien des formulaires à l'intérieur. Et aucun des composants n'est du moi le moins conçu autour du concept d'une liste de projets.

Ajout de dernière minute

Notre concepteur UX a souligné qu'il serait préférable que nous demandions une confirmation lorsque quelqu'un essaie de supprimer un projet, car cette action ne peut pas être annulée. Pas de problème, nous pouvons préparer un composant qui fait exactement cela:

<span>define(function(require) {
</span>  <span>'use strict';
</span>
  <span>var defineComponent = require('flight/lib/component');
</span>
  <span>function <span>Removable</span>() {
</span>    <span>this.defaultAttrs({
</span>      <span>'removeOn': 'uiFormProcessed',
</span>      <span>'broadcastEvents': [
</span>        <span>{'event': 'uiRemoved', 'data': {}}
</span>      <span>]
</span>    <span>});
</span>
    <span>this.after('initialize', function() {
</span>      <span>this.on(this.attr.removeOn, this.remove.bind(this));
</span>    <span>});
</span>
    <span>this.remove = function(event) {
</span>      <span>// Broadcast events to notify the rest of the UI that this component has been removed
</span>      <span>this.attr.broadcastEvents.forEach(function(eventObj) {
</span>        <span>this.trigger(eventObj.event, eventObj.data);
</span>      <span>}.bind(this));
</span>
      <span>// Animate row removal, remove DOM node, teardown component
</span>      $<span>.when(this.$node
</span>        <span>.animate({'opacity': 0}, 'fast')
</span>        <span>.slideUp('fast')
</span>      <span>).done(function() {
</span>        <span>this.$node.remove();
</span>      <span>}.bind(this));
</span>    <span>};
</span>  <span>}
</span>
  <span>return defineComponent(Removable);
</span><span>});</span>
Copier après la connexion

attachez cela aux boutons de suppression, et nous avons ce qu'on nous a demandé. La boîte de dialogue Confirmer interceptera le bouton et permettra la soumission du formulaire si l'utilisateur sélectionne «OK». Nous n'avons pas eu à modifier notre composant AsyncForm, car nous pouvons composer ces composants sans interférer les uns avec les autres. Dans notre code de production, nous utilisons également un composant singlesubmit sur le bouton d'action qui donne une rétroaction visuelle que le formulaire a été soumis et empêche plusieurs soumissions.

Composants finaux, tests et luminaires

Espérons que cet article a démontré comment vos projets pourraient bénéficier de la décomposition des interfaces en composants composables. Un avantage important de la conception des composants que je n'ai pas couverte est leur facilité de tests isolés, alors voici les composants finaux avec leurs tests de jasmin et les tests de test HTML:

  • asyncform
  • amovible
  • Count
  • Confirmer

Si vous avez des questions sur ce que j'ai couvert, veuillez demander des détails dans les commentaires et je ferai de mon mieux pour aider.

Les questions fréquemment posées (FAQ) sur les composants de pensée

Quelles sont les composantes clés de la pensée efficace?

La pensée efficace est un processus multiforme qui implique plusieurs composants clés. Il s'agit notamment de la clarté, de la précision, de la précision, de la pertinence, de la profondeur, de l'étendue, de la logique, de la signification et de l'équité. Chacun de ces composants joue un rôle crucial pour garantir que notre processus de réflexion est efficace et conduit à des conclusions précises.

Comment puis-je améliorer mes compétences de pensée critique?

Améliorer les compétences de pensée critique implique de pratiquer certains Des habitudes telles que les hypothèses de remise en question, la recherche de perspectives diverses et le fait d'être ouvert à de nouvelles idées. Cela implique également de développer des compétences telles que l'analyse, l'interprétation, l'inférence, l'évaluation, l'explication et l'autorégulation.

Quel est le rôle de la logique dans la pensée critique?

La logique est une composante fondamentale de pensée critique. Cela implique la capacité de raisonner correctement, de tirer des conclusions des prémisses, d'évaluer les réclamations et d'éviter les erreurs ou les erreurs de raisonnement.

Comment la pertinence contribue-t-elle à une pensée efficace?

La pertinence garantit que la pertinence est-elle Les informations ou idées que nous considérons sont directement liées au problème ou au problème à accomplir. Il nous aide à rester concentrés et à éviter les distractions ou les informations non pertinentes.

Quelle est la signification de la profondeur dans la pensée critique?

La profondeur de la pensée critique fait référence à la capacité de plonger sous la surface d'un problème ou problème, comprendre ses causes ou implications sous-jacentes, et l'explorer sous plusieurs perspectives.

Comment puis-je développer une largeur dans ma pensée?

Développer l'étendue de la réflexion implique de considérer un large éventail de perspectives, d'idées et de sources d'information. Il faut être ouvert d'esprit, curieux et disposé à explorer de nouvelles idées ou points de vue.

Quel est le rôle de l'équité dans la pensée critique?

L'équité dans la pensée critique implique d'être impartiale, impartiale, et objectif. Il nous oblige à considérer tous les points de vue et preuves pertinents, et pour éviter le favoritisme, les biais ou les préjugés.

Comment la précision contribue-t-elle à une pensée efficace?

La précision dans la pensée implique d'être exact, détaillée et claire dans nos pensées et nos expressions. Cela nous aide à éviter l'imprécision, l'ambiguïté ou la confusion, et à communiquer efficacement nos idées.

Quelle est la signification de la précision dans la pensée critique?

La précision de la pensée critique implique que nos informations , les idées et les conclusions sont correctes, fiables et exemptes d'erreurs ou de distorsions. Il est crucial pour prendre des décisions et des jugements solides.

Comment puis-je améliorer la clarté de ma réflexion?

Améliorer la clarté de la pensée implique de pratiquer une communication claire, d'éviter le jargon ou le langage complexe, et la recherche de pour simplicité et simplicité dans nos pensées et nos expressions.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal