MDC-112 Web: intégration de MDC aux frameworks Web

1. Introduction

logo_components_color_2x_web_96dp.png

Material Components (MDC) aide les développeurs à implémenter Material Design. Conçu par une équipe d'ingénieurs et de spécialistes de l'expérience utilisateur chez Google, MDC propose des dizaines de composants d'interface utilisateur élégants et fonctionnels. Il est disponible pour Android, iOS, le Web et Flutter.material.io/develop.

MDC Web est conçu pour s'intégrer à n'importe quel framework d'interface tout en respectant les principes de Material Design. L'atelier de programmation suivant vous explique comment créer un composant React qui utilise MDC Web comme base. Les principes appris dans cet atelier de programmation peuvent être appliqués à n'importe quel framework JavaScript.

Comment MDC Web est-il conçu ?

La couche JavaScript de MDC Web est composée de trois classes par composant : Component, Foundation et Adapter. Ce modèle permet à MDC Web de s'intégrer aux frameworks d'interface.

La classe Foundation contient la logique métier qui implémente Material Design. Elle ne fait référence à aucun élément HTML. Cela nous permet d'abstraire la logique d'interaction HTML dans la classe Adapter. La classe Foundation possède une classe Adapter.

La classe Adapter est une interface. L'interface Adapter est référencée par la classe Foundation pour implémenter la logique métier de Material Design. Vous pouvez implémenter la classe Adapter dans différents frameworks tels qu'Angular ou React. Une implémentation d'un adaptateur interagit avec la structure DOM.

La classe Component possède une classe Foundation et son rôle est de :

  1. implémenter la classe Adapter à l'aide de JavaScript non-framework ;
  2. fournir des méthodes publiques qui sont des proxys pour les méthodes de la classe Foundation.

Ce que fournit MDC Web

Chaque package de MDC Web est fourni avec une classe Component, Foundation et Adapter. Pour instancier une classe Component , vous devez transmettre l'élément racine element à la méthode de constructeur du composant. La classe Component implémente une classe Adapter, qui interagit avec le DOM et les éléments HTML. La classe Component instancie ensuite la classe Foundation, qui appelle les méthodes Adapter.

Pour intégrer MDC Web dans un framework, vous devez créer votre propre classe Component dans le langage/la syntaxe de ce framework. La classe Component du framework implémente la classe Adapter de MDC Web et utilise la classe Foundation de MDC Web.

Ce que vous allez créer

Cet atelier de programmation explique comment créer une classe Adapter personnalisée pour utiliser la logique Foundation afin d'obtenir un composant React Material Design. Il aborde les sujets avancés présentés dans la section Intégration dans des frameworks. React est utilisé dans cet atelier de programmation comme exemple de framework, mais cette approche peut être appliquée à n'importe quel autre framework.

Dans cet atelier de programmation, vous allez créer la barre d'application supérieure et recréer la page de démonstration de la barre d'application supérieure . La mise en page de la page de démonstration est déjà configurée. Vous pouvez donc commencer à travailler sur la barre d'application supérieure. La barre d'application supérieure comprendra les éléments suivants :

  • Icône de navigation
  • Tâches
  • Quatre variantes sont disponibles : Short (Courte), always collapsed (Toujours réduite), fixed (Fixe) et prominent (Proéminente).

Ce dont vous aurez besoin :

  • Une version récente de Node.js (fournie avec npm, un gestionnaire de packages JavaScript)
  • L'exemple de code (à télécharger à l'étape suivante)
  • Connaissances de base en HTML, CSS, JavaScript et React

Comment évalueriez-vous votre niveau d'expérience en développement Web ?

Débutant Intermédiaire Expert

2. Configurer l'environnement de développement

Télécharger l'application de départ de l'atelier de programmation

Elle se trouve dans le répertoire material-components-web-codelabs-master/mdc-112/starter.

… ou cloner l'atelier depuis GitHub

Pour cloner cet atelier de programmation à partir de GitHub, exécutez les commandes suivantes :

git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-112/starter

Installer les dépendances du projet

À partir du répertoire de démarrage material-components-web-codelabs/mdc-112/starter, exécutez la commande suivante :

npm install

Vous verrez beaucoup d'activité. À la fin, votre terminal devrait afficher une installation réussie :

22a33efc2a687408.png

Exécuter l'application de départ

Dans le même répertoire, exécutez la commande suivante :

npm start

Le webpack-dev-server démarre. Accédez à http://localhost:8080/ dans votre navigateur pour afficher la page.

b55c66dd400cf34f.png

Opération réussie ! Le code de départ de la page de démonstration React de la barre d'application supérieure devrait s'exécuter dans votre navigateur. Vous devriez voir un mur de texte lorem ipsum, une zone Controls (en bas à droite) et une barre d'application supérieure inachevée :

4ca3cf6d216f9290.png

Examiner le code et le projet

Si vous ouvrez votre éditeur de code, le répertoire du projet devrait se présenter comme suit :

e9a3270d6a67c589.png

Ouvrez le fichier App.js et examinez la méthode render, qui inclut le composant <TopAppBar> :

App.js

render() {
    const {isFixed, isShort, isRtl, isProminent, isAlwaysCollapsed, shouldReinit} = this.state;

    return (
      <section
        dir={isRtl ? 'rtl' : 'ltr'}
        className='mdc-typography'>
        {
          shouldReinit ? null :
          <TopAppBar
            navIcon={this.renderNavIcon()}
            short={isShort}
            prominent={isProminent}
            fixed={isFixed}
            alwaysCollapsed={isAlwaysCollapsed}
            title='Mountain View, CA'
            actionItems={this.actionItems}
          />
        }
        <div className={classnames('mdc-top-app-bar--fixed-adjust', {
          'mdc-top-app-bar--short-fixed-adjust': isShort || isAlwaysCollapsed,
          'mdc-top-app-bar--prominent-fixed-adjust': isProminent,
        })}>
          {this.renderDemoParagraphs()}
        </div>

        {this.renderControls()}
      </section>
    );
  }

Il s'agit du point d'entrée du TopAppBar dans l'application.

Ouvrez le fichier TopAppBar.js, qui est une classe Component React nue avec une méthode render :

TopAppBar.js

import React from 'react';

export default class TopAppBar extends React.Component {
  render() {
    return (
      <header>
        TOP APP BAR
      </header>
    );
  }
}

3. Composition du composant

Dans React, la méthode render génère le code HTML du composant. Le composant de la barre d'application supérieure affichera une balise <header /> et sera composé de deux sections principales :

  1. Section de l'icône de navigation et du titre
  2. Section des icônes d'action

Si vous avez des questions sur les éléments qui composent la barre d'application supérieure, consultez la documentation sur GitHub.

Modifiez la méthode render() dans TopAppBar.js comme suit :

  render() {
    const {
      title,
      navIcon,
    } = this.props;

    return (
      <header
        className={this.classes}
        style={this.getMergedStyles()}
        ref={this.topAppBarElement}
      >
        <div className='mdc-top-app-bar__row'>
          <section className='mdc-top-app-bar__section mdc-top-app-bar__section--align-start'>
            {navIcon ? navIcon : null}
            <span className="mdc-top-app-bar__title">
              {title}
            </span>
          </section>
          {this.renderActionItems()}
        </div>
      </header>
    );
  }

Ce code HTML comporte deux éléments de section. Le premier contient une icône de navigation et un titre. Le second contient des icônes d'action.

Ajoutez ensuite la méthode renderActionItems :

renderActionItems() {
  const {actionItems} = this.props;
  if (!actionItems) {
    return;
  }

  return (
    <section className='mdc-top-app-bar__section mdc-top-app-bar__section--align-end' role='toolbar'>
      {/* need to clone element to set key */}
      {actionItems.map((item, key) => React.cloneElement(item, {key}))}
    </section>
  );
}

Un développeur importera TopAppBar dans son application React et transmettra des icônes d'action à l'élément TopAppBar. Vous pouvez voir un exemple de code initialisant un TopAppBar dans App.js.

La méthode getMergedStyles est manquante. Elle est utilisée dans la méthode render. Veuillez ajouter la méthode JavaScript suivante à la classe TopAppBar :

getMergedStyles = () => {
  const {style} = this.props;
  const {style: internalStyle} = this.state;
  return Object.assign({}, internalStyle, style);
}

this.classes est également absent de la méthode render, mais sera abordé dans une section ultérieure. Outre la méthode getter manquante, this.classes, vous devez encore implémenter des éléments de TopAppBar pour que la barre d'application supérieure puisse s'afficher correctement.

Les éléments du composant React qui manquent encore dans la barre d'application supérieure sont les suivants :

  • Une base initialisée
  • Méthodes d'adaptateur à transmettre à la base
  • Balisage JSX
  • Gestion des variantes (fixe, courte, toujours réduite, proéminente)

La méthode

  1. Implémentez les méthodes Adapter.
  2. Initialisez la classe Foundation dans componentDidMount.
  3. Appelez la méthode Foundation.destroy dans componentWillUnmount.
  4. Établissez la gestion des variantes via une méthode getter qui combine les noms de classe appropriés.

4. Implémenter les méthodes d'adaptateur

Le TopAppBar composant JS non-framework implémente les méthodes Adapter suivantes (listées en détail ici) :

  • hasClass()
  • addClass()
  • removeClass()
  • registerNavigationIconInteractionHandler()
  • deregisterNavigationIconInteractionHandler()
  • notifyNavigationIconClicked()
  • setStyle()
  • getTopAppBarHeight()
  • registerScrollHandler()
  • deregisterScrollHandler()
  • registerResizeHandler()
  • deregisterResizeHandler()
  • getViewportScrollY()
  • getTotalActionItems()

Étant donné que React comporte des événements synthétiques, ainsi que des bonnes pratiques et des modèles de codage différents, les méthodes Adapter doivent être réimplémentées.

Méthode getter d'adaptateur

Dans le fichier TopAppBar.js, ajoutez la méthode JavaScript suivante à TopAppBar :

get adapter() {
  const {actionItems} = this.props;

  return {
    hasClass: (className) => this.classes.split(' ').includes(className),
    addClass: (className) => this.setState({classList: this.state.classList.add(className)}),
    removeClass: (className) => {
      const {classList} = this.state;
      classList.delete(className);
      this.setState({classList});
    },
    setStyle: this.setStyle,
    getTopAppBarHeight: () => this.topAppBarElement.current.clientHeight,
    registerScrollHandler: (handler) => window.addEventListener('scroll', handler),
    deregisterScrollHandler: (handler) => window.removeEventListener('scroll', handler),
    registerResizeHandler: (handler) => window.addEventListener('resize', handler),
    deregisterResizeHandler: (handler) => window.removeEventListener('resize', handler),
    getViewportScrollY: () => window.pageYOffset,
    getTotalActionItems: () => actionItems && actionItems.length,
  };
}

Les API d'adaptateur pour l'enregistrement des événements de défilement et de redimensionnement sont implémentées de manière identique à la version JS non-framework, car React ne comporte aucun événement synthétique pour le défilement ou le redimensionnement et renvoie au système d'événements DOM natif. getViewPortScrollY doit également renvoyer au DOM natif, car il s'agit d'une fonction sur l'objet window, qui ne figure pas dans l'API de React. Les implémentations d'adaptateur seront différentes pour chaque framework.

Vous remarquerez peut-être que this.setStyle est manquant. Il est appelé par la méthode get adapter. Dans le fichier TopAppBar.js, ajoutez la méthode JavaScript manquante à la classe TopAppBar :

setStyle = (varName, value) => {
  const updatedStyle = Object.assign({}, this.state.style);
  updatedStyle[varName] = value;
  this.setState({style: updatedStyle});
}

Vous venez d'implémenter la classe Adapter. Notez que des erreurs peuvent s'afficher dans votre console à ce stade, car l'implémentation complète n'est pas encore terminée. La section suivante vous explique comment ajouter et supprimer des classes CSS.

5. Implémenter les méthodes de composant

Gérer les variantes et les classes

React ne dispose pas d'API pour gérer les classes. Pour imiter les méthodes d'ajout/de suppression de classes CSS de JavaScript natif, ajoutez la variable d'état classList. Trois éléments de code dans TopAppBar interagissent avec les classes CSS :

  1. Composant <TopAppBar /> via la propriété className
  2. Méthode Adapter via addClass ou removeClass
  3. Codage en dur dans le composant React <TopAppBar />

Tout d'abord, ajoutez l'importation suivante en haut de TopAppBar.js, sous les importations existantes :

import classnames from 'classnames';

Ajoutez ensuite le code suivant dans la déclaration de classe du composant TopAppBar :

export default class TopAppBar extends React.Component {
  constructor(props) {
    super(props);
    this.topAppBarElement = React.createRef();
  }

  state = {
    classList: new Set(),
    style: {},
  };

  get classes() {
    const {classList} = this.state;
    const {
      alwaysCollapsed,
      className,
      short,
      fixed,
      prominent,
    } = this.props;

    return classnames('mdc-top-app-bar', Array.from(classList), className, {
      'mdc-top-app-bar--fixed': fixed,
      'mdc-top-app-bar--short': short,
      'mdc-top-app-bar--short-collapsed': alwaysCollapsed,
      'mdc-top-app-bar--prominent': prominent,
    });
  }

  ... 
}

Si vous accédez à http://localhost:8080, les cases à cocher "Controls" devraient maintenant activer/désactiver les noms de classe du DOM.

Ce code rend TopAppBar utilisable par de nombreux développeurs. Les développeurs peuvent interagir avec l'API TopAppBar sans se soucier des détails d'implémentation des classes CSS.

Vous avez implémenté l'adaptateur. La section suivante vous explique comment instancier une classe Foundation.

Installer et désinstaller le composant

L'instanciation de la classe Foundation se produit dans la méthode componentDidMount.

Tout d'abord, importez les bases de la barre d'application supérieure MDC en ajoutant l'importation suivante après les importations existantes dans TopAppBar.js :

import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';

Ajoutez ensuite le code JavaScript suivant à la classe TopAppBar :

export default class TopAppBar extends React.Component {
 
  ... 

  foundation_ = null;

  componentDidMount() {
    this.initializeFoundation();
  }

  componentWillUnmount() {
    this.foundation_.destroy();
  }

  initializeFoundation = () => {
    if (this.props.short) {
      this.foundation_ = new MDCShortTopAppBarFoundation(this.adapter);
    } else if (this.props.fixed) {
      this.foundation_ = new MDCFixedTopAppBarFoundation(this.adapter);
    } else {
      this.foundation_ = new MDCTopAppBarFoundation(this.adapter);
    }

    this.foundation_.init();
  }
 
  ... 

}

Une bonne pratique de codage React consiste à définir des propTypes et des defaultProps. Ajoutez l'importation suivante après les importations existantes dans TopAppBar.js :

import PropTypes from 'prop-types';

Ajoutez ensuite le code suivant en bas de TopAppBar.js (après la classe Component) :

import PropTypes from 'prop-types';

TopAppBar.propTypes = {
  alwaysCollapsed: PropTypes.bool,
  short: PropTypes.bool,
  fixed: PropTypes.bool,
  prominent: PropTypes.bool,
  title: PropTypes.string,
  actionItems: PropTypes.arrayOf(PropTypes.element),
  navIcon: PropTypes.element,
};

TopAppBar.defaultProps = {
  alwaysCollapsed: false,
  short: false,
  fixed: false,
  prominent: false,
  title: '',
  actionItems: null,
  navIcon: null,
};

Vous avez implémenté le composant React de la barre d'application supérieure. Si vous accédez à http://localhost:8080, vous pouvez utiliser la page de démonstration. La page de démonstration fonctionnera de la même manière que la page de démonstration de MDC Web. La page de démonstration devrait se présenter comme suit :

3d983b98c2092e7a.png

6. Conclusion

Dans ce tutoriel, nous avons expliqué comment encapsuler la classe Foundation de MDC Web pour l'utiliser dans une application React. Il existe quelques bibliothèques sur GitHub et npm qui encapsulent les composants MDC Web, comme décrit dans la section Intégration dans des frameworks. Nous vous recommandons d'utiliser la liste disponible ici. Cette liste inclut également d'autres frameworks que React, tels qu'Angular et Vue.

Ce tutoriel met en évidence notre décision de diviser le code MDC Web en trois parties : Foundation, Adapter et Component. Cette architecture permet aux composants de partager du code commun tout en fonctionnant avec tous les frameworks. Merci d'avoir essayé Material Components React. N'hésitez pas à consulter notre nouvelle bibliothèque MDC React. Nous espérons que cet atelier de programmation vous a plu.

La réalisation de cet atelier de programmation m'a demandé un temps et des efforts raisonnables

Tout à fait d'accord D'accord Ni d'accord, ni pas d'accord Pas d'accord Pas du tout d'accord

Je souhaite continuer à utiliser Material Components

Tout à fait d'accord D'accord Ni d'accord, ni pas d'accord Pas d'accord Pas du tout d'accord