MDC-112 Web: Integration von MDC in Web-Frameworks

1. Einführung

logo_components_color_2x_web_96dp.png

Mit Material Components (MDC) können Entwickler Material Design implementieren. MDC wurde von einem Team von Entwicklern und UX-Designern bei Google entwickelt und bietet Dutzende ansprechender und funktionaler UI-Komponenten. Es ist für Android, iOS, Web und Flutter verfügbar.material.io/develop

MDC Web wurde für die Integration in jedes Frontend-Framework entwickelt, wobei die Prinzipien des Material Design aufrechterhalten werden. Im folgenden Codelab erfahren Sie, wie Sie eine React-Komponente erstellen, die auf MDC Web basiert. Die in diesem Codelab vermittelten Prinzipien können auf jedes JavaScript-Framework angewendet werden.

So funktioniert MDC Web

Die JavaScript-Ebene von MDC Web besteht aus drei Klassen pro Komponente: Component, Foundation und Adapter. Durch dieses Muster kann MDC Web flexibel in Frontend-Frameworks integrieren.

Die Foundation enthält die Geschäftslogik, die Material Design implementiert. Die Foundation verweist nicht auf HTML-Elemente. So können wir die HTML-Interaktionslogik in den Adapter abstrahieren. Foundation hat einen Adapter.

Der Adapter ist eine Schnittstelle. Die Adapter-Schnittstelle wird von der Foundation zur Implementierung der Material Design-Geschäftslogik verwendet. Sie können den Adapter in verschiedenen Frameworks wie Angular oder React implementieren. Eine Adapterimplementierung interagiert mit der DOM-Struktur.

Die Komponente hat eine Grundlage und ihre Aufgabe besteht darin,

  1. Implementieren Sie den Adapter mithilfe von Nicht-Framework-JavaScript und
  2. Stellen Sie öffentliche Methoden bereit, die auf Methoden in der Foundation verweisen.

Was MDC Web bietet

Jedes Paket in MDC Web enthält eine Komponente, eine Grundlage und einen Adapter. Wenn Sie eine Komponente instanziieren möchten, müssen Sie der Konstruktormethode der Komponente das Stammelement übergeben. Die Komponente implementiert einen Adapter, der mit den DOM- und HTML-Elementen interagiert. Die Component instanziiert dann die Foundation, wodurch die Adapter-Methoden aufgerufen werden.

Wenn Sie MDC Web in ein Framework einbinden möchten, müssen Sie Ihre eigene Komponente in der Sprache/Syntax dieses Frameworks erstellen. Die Komponente des Frameworks implementiert den Adapter von MDC Web und verwendet die Foundation von MDC Web.

Umfang

In diesem Codelab wird gezeigt, wie Sie einen benutzerdefinierten Adapter erstellen, um die Foundation-Logik für eine Material Design-React-Komponente zu verwenden. Er behandelt die weiterführenden Themen unter In Frameworks integrieren. In diesem Codelab wird React als Beispiel-Framework verwendet, aber dieser Ansatz kann auf jedes andere Framework angewendet werden.

In diesem Codelab erstellen Sie die obere App-Leiste und die Demoseite für die obere App-Leiste neu. Das Layout der Demoseite ist bereits eingerichtet, sodass Sie mit der Arbeit an der oberen App-Leiste beginnen können. Die obere App-Leiste enthält Folgendes:

  • Navigationssymbol
  • Maßnahmen
  • Es gibt vier Varianten: kurze, immer minimiert, feste und gut sichtbare Varianten.

Sie benötigen:

  • Eine aktuelle Version von Node.js (im Lieferumfang von npm, einem JavaScript-Paketmanager)
  • Beispielcode (wird im nächsten Schritt heruntergeladen)
  • Grundkenntnisse in HTML, CSS, JavaScript und React

Wie würden Sie Ihre Erfahrung mit der Webentwicklung bewerten?

Anfänger Mittelstufe Fortgeschritten

2. Entwicklungsumgebung einrichten

Codelab-App für den Einstieg herunterladen

Die Starter-App befindet sich im Verzeichnis material-components-web-codelabs-master/mdc-112/starter.

…oder es aus GitHub klonen

Führen Sie die folgenden Befehle aus, um dieses Codelab von GitHub zu klonen:

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

Projektabhängigkeiten installieren

Führen Sie im Startverzeichnis material-components-web-codelabs/mdc-112/starter Folgendes aus:

npm install

Sie sehen viele Aktivitäten und am Ende sollte im Terminal eine erfolgreiche Installation angezeigt werden:

22a33efc2a687408.png

Start-App ausführen

Führen Sie im selben Verzeichnis Folgendes aus:

npm start

webpack-dev-server wird gestartet. Rufen Sie die Seite mit Ihrem Browser unter http://localhost:8080/ auf.

b55c66dd400cf34f.png

Fertig! Der Startercode für die React-Demoseite der oberen App-Leiste sollte in Ihrem Browser ausgeführt werden. Sie sollten eine Wand mit lorem ipsum-Text, ein Feld Steuerelemente (unten rechts) und eine unfertige obere App-Leiste sehen:

4ca3cf6d216f9290.png

Code und Projekt ansehen

Wenn Sie Ihren Code-Editor öffnen, sollte das Projektverzeichnis in etwa so aussehen:

e9a3270d6a67c589.png

Öffnen Sie die Datei App.js und sehen Sie sich die Methode render an, die die Komponente <TopAppBar> enthält:

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

Dies ist der Einstiegspunkt für die TopAppBar in der Anwendung.

Öffnen Sie die Datei TopAppBar.js. Dies ist eine einfache React-Component-Klasse mit einer render-Methode:

TopAppBar.js

import React from 'react';

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

3. Zusammensetzung der Komponente

In React gibt die Methode render den HTML-Code der Komponente aus. Die Komponente der oberen App-Leiste rendert ein <header />-Tag und besteht aus zwei Hauptabschnitten:

  1. Navigationssymbol und Titelbereich
  2. Bereich für Aktionssymbole

Weitere Informationen zu den Elementen der oberen App-Leiste finden Sie in der Dokumentation auf GitHub.

Ändern Sie die Methode render() in TopAppBar.js so:

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

Dieses HTML-Dokument enthält zwei Abschnittselemente. Die erste enthält ein Navigationssymbol und einen Titel. Die zweite enthält Aktionssymbole.

Fügen Sie als Nächstes die Methode renderActionItems hinzu:

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

Ein Entwickler importiert TopAppBar in seine React-Anwendung und übergibt Aktionssymbole an das TopAppBar-Element. Im Beispielcode wird eine TopAppBar in App.js initialisiert.

Die Methode getMergedStyles fehlt, die in der Methode render verwendet wird. Fügen Sie der Klasse TopAppBar die folgende JavaScript-Methode hinzu:

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

this.classes fehlt auch in der Methode render, wird aber in einem späteren Abschnitt behandelt. Neben der fehlenden Getter-Methode this.classes müssen Sie noch Teile der TopAppBar implementieren, damit die obere App-Leiste richtig gerendert werden kann.

In der oberen App-Leiste fehlen noch folgende Teile der React-Komponente:

  • Eine initialisierte Grundlage
  • Adaptermethoden, die an die Foundation übergeben werden
  • JSX-Markup
  • Variantenverwaltung (fixiert, kurz, immer minimiert, gut sichtbar)

Der Ansatz

  1. Implementieren Sie die Adapter-Methoden.
  2. Initialisieren Sie die Grundlage in der componentDidMount.
  3. Rufen Sie die Methode Foundation.destroy in der componentWillUnmount auf.
  4. Legen Sie die Variantenverwaltung über eine Getter-Methode fest, die die entsprechenden Klassennamen kombiniert.

4. Adaptermethoden implementieren

Die nicht-Framework-JS-Komponente TopAppBar implementiert die folgenden Adapter-Methoden, die hier ausführlich aufgeführt sind:

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

Da React synthetische Ereignisse und andere Best Practices für die Programmierung sowie -muster hat, müssen die Adapter-Methoden neu implementiert werden.

Adapter-Getter-Methode

Fügen Sie in der Datei TopAppBar.js der Variablen TopAppBar die folgende JavaScript-Methode hinzu:

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

Die Adapter-APIs für die Registrierung von Scroll- und Größenänderungsereignissen werden identisch mit der JS-Version ohne Framework implementiert, da React keine synthetischen Ereignisse zum Scrollen oder Ändern der Größe hat und stattdessen das native DOM-Ereignissystem verwendet. getViewPortScrollY muss auch an das native DOM übergeben werden, da es sich um eine Funktion des window-Objekts handelt, das nicht in der React-API enthalten ist. Die Adapterimplementierungen unterscheiden sich je nach Framework.

Möglicherweise ist this.setStyle nicht vorhanden, das von der Methode get adapter aufgerufen wird. Fügen Sie in der Datei TopAppBar.js der Klasse TopAppBar die fehlende JavaScript-Methode hinzu:

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

Sie haben gerade den Adapter implementiert. Möglicherweise werden in der Konsole Fehler angezeigt, da die vollständige Implementierung noch nicht abgeschlossen ist. Im nächsten Abschnitt erfahren Sie, wie Sie CSS-Klassen hinzufügen und entfernen.

5. Komponentenmethoden implementieren

Varianten und Klassen verwalten

React hat keine API zum Verwalten von Klassen. Fügen Sie die Statusvariable classList hinzu, um die CSS-Klassenmethoden des nativen JavaScript-Codes zu imitieren. In TopAppBar gibt es drei Code-Abschnitte, die mit CSS-Klassen interagieren:

  1. <TopAppBar />-Komponente über das Attribut className.
  2. Die Methode Adapter über addClass oder removeClass
  3. In der <TopAppBar />-React-Komponente hartcodiert.

Fügen Sie zuerst den folgenden Import oben in TopAppBar.js unter den vorhandenen Importen hinzu:

import classnames from 'classnames';

Fügen Sie dann den folgenden Code in die Klassendeklaration der TopAppBar-Komponente ein:

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

  ... 
}

Wenn Sie http://localhost:8080 aufrufen, können Sie mit den Steuerelementen die Klassennamen im DOM aktivieren bzw. deaktivieren.

Dieser Code macht TopAppBar für viele Entwickler nutzbar. Entwickler können mit der TopAppBar API interagieren, ohne sich um die Implementierungsdetails von CSS-Klassen kümmern zu müssen.

Sie haben den Adapter jetzt erfolgreich implementiert. Im nächsten Abschnitt erfahren Sie, wie Sie eine Foundation instanziieren.

Komponente bereitstellen und trennen

Die Instanziierung Foundation erfolgt in der Methode componentDidMount.

Importieren Sie zuerst die Grundlagen der MDC Top App Bar. Fügen Sie dazu den folgenden Import nach den vorhandenen Importen in TopAppBar.js hinzu:

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

Fügen Sie als Nächstes den folgenden JavaScript-Code in die Klasse TopAppBar ein:

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

}

Eine gute React-Programmierpraxis besteht darin, propTypes und defaultProps zu definieren. Fügen Sie den folgenden Import nach den vorhandenen Importen in TopAppBar.js hinzu:

import PropTypes from 'prop-types';

Fügen Sie dann den folgenden Code unter TopAppBar.js (nach der Component-Klasse) ein:

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

Sie haben die Top App Bar React-Komponente erfolgreich implementiert. Wenn Sie http://localhost:8080 aufrufen, können Sie die Demoseite ausprobieren. Die Demoseite funktioniert genauso wie die Demoseite von MDC Web. Die Demoseite sollte so aussehen:

3d983b98c2092e7a.png

6. Zusammenfassung

In dieser Anleitung haben wir gezeigt, wie Sie die Foundation von MDC Web für die Verwendung in einer React-Anwendung einbinden. Es gibt einige Bibliotheken auf GitHub und npm, die MDC-Webkomponenten umschließen, wie unter In Frameworks integrieren beschrieben. Wir empfehlen, diese Liste zu verwenden. Diese Liste enthält neben React auch andere Frameworks wie Angular und Vue.

In dieser Anleitung wird unsere Entscheidung erläutert, den MDC-Webcode in drei Teile zu unterteilen: Grundlage, Adapter und Komponente. Diese Architektur ermöglicht es Komponenten, gemeinsamen Code zu nutzen, während sie mit allen Frameworks arbeiten. Vielen Dank, dass Sie Material Components React ausprobiert haben. Sehen Sie sich auch unsere neue Bibliothek MDC React an. Wir hoffen, dass Ihnen dieses Codelab gefallen hat.

Ich konnte dieses Codelab mit angemessenem Zeitaufwand und Mühe abschließen.

Stimme voll zu Stimme zu Neutral Stimme nicht zu Stimme überhaupt nicht zu

Ich möchte Material Components auch in Zukunft verwenden

Stimme vollkommen zu Stimme zu Neutral Stimme nicht zu Stimme überhaupt nicht zu