MDC-112 Web: integrazione di MDC con framework web

1. Introduzione

logo_components_color_2x_web_96dp.png

Material Components (MDC) consente agli sviluppatori di implementare Material Design. Creato dal team di ingegneri e designer UX di Google, MDC è dotato di decine di componenti UI belli e funzionali ed è disponibile per Android, iOS, web e Flutter.material.io/develop

MDC Web è progettato per integrarsi in qualsiasi framework front-end rispettando i principi del Material Design. Il seguente codelab ti guida nella creazione di un componente React, che utilizza MDC Web come base. I principi appresi in questo codelab possono essere applicati a qualsiasi framework JavaScript.

Come viene creato MDC Web

Il livello JavaScript di MDC Web è composto da tre classi per componente: Componente, Base e Adattatore. Questo pattern offre a MDC Web la flessibilità per integrarsi con i framework di frontend.

La sezione Elementi di base contiene la logica di business che implementa il Material Design. La sezione Elementi di base non fa riferimento ad alcun elemento HTML. In questo modo possiamo astrarre la logica di interazione HTML nell'adattatore. Foundation ha un adattatore.

L'adattatore è un'interfaccia. La Foundation fa riferimento all'interfaccia dell'adattatore per implementare la logica di business di Material Design. Puoi implementare l'Adapter in diversi framework, ad esempio Angular o React. Un'implementazione di un adattatore interagisce con la struttura DOM.

Il componente ha una base e il suo ruolo è quello di

  1. Implementare l'adattatore, utilizzando JavaScript non framework
  2. Fornisci metodi pubblici che eseguono il proxy ai metodi in Foundation.

Cosa offre MDC Web

Ogni pacchetto di MDC Web include un componente, una base e un adattatore. Per creare un'istanza di un Componente, devi passare l'elemento radice al metodo costruttore del componente. Il componente implementa un adattatore, che interagisce con gli elementi DOM e HTML. Il componente crea quindi un'istanza della base Foundation, che chiama i metodi Adapter.

Per integrare MDC Web in un framework, devi creare il tuo componente nel linguaggio/sintassi del framework in questione. Il componente del framework implementa Adapter di MDC Web e utilizza Foundation di MDC Web.

Cosa creerai

Questo codelab mostra come creare un adattatore personalizzato per utilizzare la logica Foundation per ottenere un componente di reazione Material Design. Tratta gli argomenti avanzati disponibili in Integrazione nei framework. La reazione viene utilizzata in questo codelab come framework di esempio, ma questo approccio può essere applicato a qualsiasi altro framework.

In questo codelab, creerai la barra delle app nella parte superiore e ricrei quella della pagina demo della barra superiore. Il layout della pagina demo è già configurato, quindi puoi iniziare a lavorare sulla barra delle app in alto. La barra delle app in alto includerà:

  • Icona di navigazione
  • Attività
  • Sono disponibili 4 varianti: corta, sempre compressa, fissa ed in evidenza.

Che cosa ti serve:

  • Una versione recente di Node.js (incorporata in bundle con npm, un gestore di pacchetti JavaScript)
  • Il codice campione (da scaricare nel passaggio successivo)
  • Conoscenza di base di HTML, CSS, JavaScript e React

Come giudichi il tuo livello di esperienza nello sviluppo web?

Principiante Livello intermedio Eccellente

2. Configura ambiente di sviluppo

Scarica l'app codelab iniziale

L'app iniziale si trova nella directory material-components-web-codelabs-master/mdc-112/starter.

...o clonarlo da GitHub

Per clonare questo codelab da GitHub, esegui questi comandi:

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

Installa le dipendenze del progetto

Dalla directory iniziale material-components-web-codelabs/mdc-112/starter, esegui:

npm install

Vedrai molta attività e, alla fine, il tuo terminale dovrebbe mostrare un'installazione eseguita correttamente:

22a33efc2a687408.png

Esegui l'app iniziale

Nella stessa directory, esegui:

npm start

Verrà avviato webpack-dev-server. Visita il sito http://localhost:8080/ nel browser per visualizzare la pagina.

b55c66dd400cf34f.png

Operazione riuscita. Il codice di avvio per la pagina React Demo sulla barra delle app superiore dovrebbe essere in esecuzione nel browser. Dovresti vedere un wall di testo lorem ipsum, una casella Controlli (in basso a destra) e una barra delle app in alto non completata:

4ca3cf6d216f9290.png

Dai un'occhiata al codice e al progetto

Se apri l'editor di codice, la directory del progetto dovrebbe essere simile a questa:

e9a3270d6a67c589.png

Apri il file App.js e osserva il metodo render, che include il componente <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>
    );
  }

Questo è il punto di ingresso per TopAppBar nell'applicazione.

Apri il file TopAppBar.js, che è una classe Component semplice con un metodo render:

TopAppBar.js

import React from 'react';

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

3. Composizione del componente

In React, il metodo render restituisce l'HTML del componente. Il componente Barra delle app in alto mostrerà un tag <header /> e sarà composto da due sezioni principali:

  1. Icona di navigazione e sezione del titolo
  2. Sezione delle icone di azione

Se hai domande sugli elementi che compongono la barra delle app nella parte superiore, consulta la documentazione su GitHub.

Modifica il metodo render() in TopAppBar.js in modo che abbia il seguente aspetto:

  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>
    );
  }

Il codice HTML contiene due elementi di sezione. Il primo contiene un'icona di navigazione e un titolo. mentre il secondo contiene icone di azione.

Poi, aggiungi il metodo 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>
  );
}

Uno sviluppatore importerà TopAppBar nella propria applicazione React e trasmetterà le icone di azione all'elemento TopAppBar. Puoi vedere un esempio di codice durante l'inizializzazione di un TopAppBar in App.js.

Manca il metodo getMergedStyles, già utilizzato nel metodo render. Aggiungi il seguente metodo JavaScript alla classe TopAppBar:

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

Anche this.classes non è presente nel metodo render, ma verrà trattato in una sezione successiva. Oltre al metodo getter mancante, this.classes, è necessario implementare alcune parti della TopAppBar prima che la barra delle app superiore possa essere visualizzata correttamente.

Le parti del componente React che mancano ancora nella barra delle app in alto sono:

  • Una base inizializzata
  • Metodi di adattatore da usare per accedere agli elementi di base
  • Markup JSX
  • Gestione delle varianti (fissa, breve, sempre compressa, in evidenza)

L'approccio

  1. Implementa i metodi Adapter.
  2. Inizializza la base in componentDidMount.
  3. Chiama il metodo Foundation.destroy in componentWillUnmount.
  4. Stabilisci la gestione delle varianti tramite un metodo getter che combina nomi di classi appropriati.

4. Implementa metodi dell'adattatore

Il componente JS TopAppBar non non framework implementa i seguenti metodi Adapter (elencati in dettaglio qui):

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

Poiché React ha eventi sintetici e diversi pattern e best practice di programmazione diversi, è necessario reimplementare i metodi dell'adattatore.

Metodo getter dell'adattatore

Nel file TopAppBar.js, aggiungi il seguente metodo JavaScript a 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,
  };
}

Le API adattatori per la registrazione degli eventi di scorrimento e ridimensionamento sono implementate in modo identico alla versione JS non framework, perché React non ha nessun evento sintetico per lo scorrimento o il ridimensionamento, che rimanda al sistema di eventi DOM nativo. getViewPortScrollY deve anche rimandare al DOM nativo poiché è una funzione sull'oggetto window, che non è presente nell'API di React. Le implementazioni dell'adattatore saranno diverse per ogni framework.

Potresti notare che manca this.setStyle, chiamato dal metodo get adapter. Nel file TopAppBar.js, aggiungi il metodo JavaScript mancante alla classe TopAppBar:

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

Hai appena implementato l'adattatore. Tieni presente che a questo punto potresti visualizzare errori nella console perché l'implementazione completa non è ancora completa. La prossima sezione illustra come aggiungere e rimuovere le classi CSS.

5. Implementa metodi Component

Gestione di varianti e classi

React non ha un'API per gestire i corsi. Per imitare i metodi delle classi CSS di aggiunta/rimozione del codice JavaScript nativo, aggiungi la variabile di stato classList. Ci sono tre porzioni di codice in TopAppBar che interagiscono con le classi CSS:

  1. <TopAppBar /> tramite la proprietà className.
  2. Il metodo Adapter tramite addClass o removeClass.
  3. Impostazione hardcoded all'interno del componente React di <TopAppBar />.

Innanzitutto, aggiungi la seguente importazione all'inizio di TopAppBar.js, sotto le importazioni esistenti:

import classnames from 'classnames';

Quindi aggiungi il seguente codice nella dichiarazione della classe del componente 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,
    });
  }

  ... 
}

Se passi a http://localhost:8080, le caselle di controllo dei controlli dovrebbero ora attivare/disattivare i nomi delle classi dal DOM.

Questo codice rende TopAppBar utilizzabile da molti sviluppatori. Gli sviluppatori possono interagire con l'API TopAppBar, senza doversi preoccupare dei dettagli di implementazione delle classi CSS.

Hai implementato correttamente l'adattatore. La sezione successiva ti guiderà nella creazione di un'istanza di un elemento Foundation.

Montaggio e smontaggio del componente

L'istanza di Foundation viene eseguita nel metodo componentDidMount.

Innanzitutto, importa gli elementi di base della barra delle app principali dell'MDC aggiungendo la seguente importazione dopo le importazioni esistenti in TopAppBar.js:

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

Poi, aggiungi il seguente codice JavaScript alla 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();
  }
 
  ... 

}

Una buona pratica di programmazione di React è definire propTypes e defaultProps. Aggiungi la seguente importazione dopo le importazioni esistenti in TopAppBar.js:

import PropTypes from 'prop-types';

Quindi, aggiungi il seguente codice in fondo a TopAppBar.js (dopo la classe Componente):

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,
};

Hai implementato correttamente il componente Reazione della barra delle app superiore. Se vai all'indirizzo http://localhost:8080 puoi utilizzare la pagina demo. La pagina demo funziona come la pagina demo di MDC Web. La pagina demo dovrebbe avere il seguente aspetto:

3d983b98c2092e7a.png

6. Conclusione

In questo tutorial abbiamo visto come eseguire il wrapping di Foundation di MDC Web per l'utilizzo in un'applicazione React. Su GitHub e npm esistono alcune librerie che aggregano i componenti web MDC, come descritto in Integrazione nei framework. Ti consigliamo di utilizzare l'elenco disponibile qui. Questo elenco include anche altri framework oltre a React, come Angular e Vue.

Questo tutorial evidenzia la nostra decisione di suddividere il codice web MDC in tre parti: Foundation, Adattatore e Componente. Questa architettura consente ai componenti di condividere codice comune lavorando con tutti i framework. Grazie per aver provato Material Components React; dai un'occhiata alla nostra nuova libreria MDC React. Speriamo che questo codelab ti sia piaciuto.

Ho completato questo codelab con una quantità di tempo e di sforzi ragionevoli

Totalmente d'accordo D'accordo Né chiara, né confusa In disaccordo Totalmente in disaccordo

Vorrei continuare a utilizzare Material Components in futuro

Totalmente d'accordo D'accordo Né chiara, né confusa In disaccordo Totalmente in disaccordo