MDC-112 Web: integrowanie MDC z platformami sieciowymi

1. Wprowadzenie

logo_components_color_2x_web_96dp.png

Material Komponenty (MDC) pomagają deweloperom wdrażać interfejs Material Design. MDC, stworzona przez zespół inżynierów i projektantów UX w Google, zawiera dziesiątki pięknych i funkcjonalnych komponentów interfejsu. Jest dostępny na Androida, iOS, internet oraz Flutter.material.io/develop

Usługa MDC Web została zaprojektowana tak, aby można było zintegrować ją z każdą platformą frontendową przy jednoczesnym zachowaniu zasad Material Design. Dzięki poniższym ćwiczeniom w Codelabs dowiesz się, jak utworzyć komponent React, którego podstawą jest MDC Web. Zasady omówione w ramach tego ćwiczenia z programowania można zastosować w dowolnej platformie JavaScript.

Jak zbudowana jest usługa MDC Web

Warstwa JavaScript w MDC Web składa się z 3 klas na komponent: Komponent, Podstawy i Adapter. Ten wzorzec zapewnia MDC Web elastyczność w zakresie integracji z platformami frontendu.

Foundation zawiera logikę biznesową implementującą Material Design. Fundacja nie odwołuje się do żadnych elementów HTML. Pozwala to nam przedstawić abstrakcyjną logikę interakcji HTML do Adaptera. Podstawy ma adapter.

Adapter to interfejs. Foundation odwołuje się do interfejsu adaptera w celu implementacji logiki biznesowej Material Design. Adapter możesz zastosować w różnych platformach, np. Angular lub React. Implementacja adaptera współdziała ze strukturą DOM.

Komponent ma podstawę, a jego zadaniem jest

  1. Zaimplementuj Adapter, używając kodu JavaScript nieopartego na ramce.
  2. Podaj metody publiczne pośredniczące w metodach podanych w Podstawach.

Co zapewnia MDC Web

Każdy pakiet w MDC Web ma komponent, podstawę i adapter. Aby utworzyć wystąpienie komponentu, należy przekazać element główny do metody konstruktora komponentu. Komponent implementuje Adapter, który współdziała z elementami DOM i HTML. Następnie Komponent tworzy instancję Foundation, która wywołuje metody Adapter.

Aby zintegrować MDC Web ze platformą, musisz utworzyć własny komponent w wybranym języku/składni. Platforma Komponent implementuje Adapter MDC Web i używa protokołu Foundation sieci MDC.

Co utworzysz

Te ćwiczenia w Codelabs pokazują, jak stworzyć niestandardowy Adapter, który będzie wykorzystywał logikę Foundation do uzyskania komponentu Material Design React. Omawiamy w nim zaawansowane tematy dostępne na stronie Integracja z platformami (w języku angielskim). React jest używane w tym ćwiczeniu jako przykładowa platforma, ale tej metody możesz użyć w przypadku każdej innej platformy.

W ramach tego ćwiczenia w programie utworzysz pasek aplikacji u góry strony i odtworzysz stronę demonstracyjną górnego paska aplikacji. Układ strony demonstracyjnej jest już skonfigurowany, możesz więc zacząć pracę na górnym pasku aplikacji. Górny pasek aplikacji zawiera:

  • Ikona nawigacji
  • Działania
  • Dostępne są 4 wersje: krótki, zawsze zwinięty, stały i widoczny.

Co będzie Ci potrzebne:

  • najnowszą wersję Node.js (w pakiecie z npm, menedżerem pakietów JavaScript),
  • Przykładowy kod (do pobrania w następnym kroku)
  • Podstawowa znajomość języka HTML, CSS, JavaScript i React

Jak oceniasz swój poziom doświadczenia w tworzeniu stron internetowych?

Początkujący Poziom średnio zaawansowany Biegły
.

2. Skonfiguruj środowisko programistyczne

Pobierz aplikację startową z programowania

Aplikacja startowa znajduje się w katalogu material-components-web-codelabs-master/mdc-112/starter.

...lub skopiuj je z GitHuba

Aby skopiować to ćwiczenia z programowania z GitHuba, uruchom te polecenia:

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

Instalowanie zależności projektu

Z katalogu startowego material-components-web-codelabs/mdc-112/starter uruchom polecenie:

npm install

Zobaczysz dużo aktywności, a na końcu terminala powinna pojawić się wiadomość o pomyślnej instalacji:

22a33efc2a687408.png

Uruchamianie aplikacji startowej

W tym samym katalogu uruchom polecenie:

npm start

Rozpocznie się webpack-dev-server. Aby wyświetlić tę stronę, wpisz w przeglądarce adres http://localhost:8080/.

b55c66dd400cf34f.png

Gotowe! W przeglądarce powinien być uruchomiony kod startowy strony demonstracyjnej Top App Bar React. Powinna wyświetlić się ściana z tekstem lorem ipsum, pole Sterowanie (w prawym dolnym rogu) i niedokończony górny pasek aplikacji:

4ca3cf6d216f9290.png

Rzuć okiem na kod i projekt

Jeśli otworzysz edytor kodu, katalog projektu powinien wyglądać mniej więcej tak:

e9a3270d6a67c589.png

Otwórz plik App.js i sprawdź metodę render, która zawiera komponent <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>
    );
  }

Jest to punkt wejścia elementu TopAppBar w aplikacji.

Otwórz plik TopAppBar.js, który jest samą klasą React Component z metodą render:

TopAppBar.js

import React from 'react';

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

3. Skład komponentu

W reacie metoda render zwraca kod HTML komponentu. Komponent górny paska aplikacji wyrenderuje tag <header /> i składa się z 2 głównych sekcji:

  1. Ikona nawigacji i sekcja tytułu
  2. Sekcja z ikonami czynności

Jeśli masz pytania dotyczące elementów, które składają się na pasek aplikacji, zapoznaj się z dokumentacją na GitHub.

Zmodyfikuj metodę render() w TopAppBar.js, aby wyglądała tak:

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

W tym kodzie HTML znajdują się 2 elementy sekcji. Pierwszy z nich zawiera ikonę nawigacji i tytuł. Drugi zawiera ikony działań.

Następnie dodaj metodę 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>
  );
}

Programista zaimportuje plik TopAppBar do aplikacji React i przekaże ikony działań do elementu TopAppBar. Przykładowy kod inicjujący TopAppBar jest dostępny w języku App.js.

Brak metody getMergedStyles, która jest używana w metodzie render. Dodaj do klasy TopAppBar tę metodę JavaScript:

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

W metodzie render brakuje również pola this.classes, ale omówimy to w dalszej sekcji. Oprócz brakującej metody pobierania (this.classes) są jeszcze fragmenty kodu TopAppBar, które musisz wdrożyć, aby górny pasek aplikacji mógł się prawidłowo renderować.

Elementy komponentu React, których nadal brakuje na górnym pasku aplikacji:

  • Zainicjowana podstawa
  • Metody przenoszenia do podstawy
  • Znacznik JSX
  • Zarządzanie wariantami (stałe, krótkie, zawsze zwinięty, widoczne)

Realizacja

  1. Zaimplementuj metody Adapter.
  2. Zainicjuj Foundation w tabeli componentDidMount.
  3. Wywołaj metodę Foundation.destroy w tabeli componentWillUnmount.
  4. Skonfiguruj zarządzanie wariantami za pomocą metody pobierania, która łączy odpowiednie nazwy klas.

4. Wdrażanie metod związanych z adapterami

Komponent JS TopAppBar niebędący ramką implementuje te metody Adapter (wymienione szczegółowo tutaj):

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

Ponieważ React zawiera zdarzenia syntetyczne oraz różne sprawdzone metody i wzorce dotyczące kodowania, trzeba ponownie wdrożyć metody narzędzia Adapter.

Metoda pobierania adaptera

W pliku TopAppBar.js dodaj do elementu TopAppBar tę metodę JavaScriptu:

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

Interfejsy API adaptera do rejestracji zdarzeń przewijania i zmiany rozmiaru są zaimplementowane tak samo jak pozostałe wersje JavaScriptu, ponieważ React nie ma żadnego zdarzenia syntetycznego do przewijania lub zmiany rozmiaru i odracza do natywnego systemu zdarzeń DOM. Funkcja getViewPortScrollY musi też uwzględnić natywny DOM, ponieważ jest to funkcja w obiekcie window, którego nie ma w interfejsie API React. Implementacje adapterów będą się różnić w zależności od platformy.

Możesz zauważyć, że brakuje pola this.setStyle, które jest wywoływane przez metodę get adapter. W pliku TopAppBar.js dodaj brakującą metodę JavaScript do klasy TopAppBar:

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

Adapter jest już wdrożony. Pamiętaj, że w tym momencie w konsoli mogą pojawić się błędy, ponieważ pełna implementacja nie została jeszcze ukończona. W następnej sekcji dowiesz się, jak dodawać i usuwać klasy CSS.

5. Wdrażanie metod komponentów

Zarządzanie wariantami i klasami

React nie ma interfejsu API do zarządzania klasami. Aby naśladować metody dodawania i usuwania klas CSS w natywnym JavaScripcie, dodaj zmienną stanu classList. W TopAppBar są 3 fragmenty kodu, które współdziałają z klasami CSS:

  1. <TopAppBar /> za pomocą właściwości className.
  2. Metoda Adapter za pomocą addClass lub removeClass.
  3. Zakodowany na stałe w komponencie React <TopAppBar />.

Najpierw dodaj następujący import na początku listy TopAppBar.js, pod istniejącymi importami:

import classnames from 'classnames';

Następnie dodaj ten kod do deklaracji klasy w komponencie 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,
    });
  }

  ... 
}

Jeśli otworzysz stronę http://localhost:8080, pola wyboru ustawień powinny teraz włączać i wyłączać nazwy klas w DOM.

Dzięki temu kodowi TopAppBar może używać wielu deweloperów. Deweloperzy mogą korzystać z interfejsu API TopAppBar, nie martwiąc się o szczegóły implementacji klas CSS.

Udało Ci się wdrożyć adapter. W następnej sekcji dowiesz się, jak utworzyć instancję Fundacja.

Montaż i odłączanie elementu

Wystąpienie podstawowe odbywa się w metodzie componentDidMount.

Najpierw zaimportuj podstawowe informacje o pasku aplikacji MDC, dodając następujący import po dotychczasowych importach w TopAppBar.js:

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

Następnie dodaj do klasy TopAppBar ten kod JavaScript:

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

}

Jedną z dobrych metod kodowania w React jest zdefiniowanie obiektów propType i defaultProps. Po zakończeniu importowania do TopAppBar.js dodaj ten import:

import PropTypes from 'prop-types';

Następnie dodaj ten kod na końcu TopAppBar.js (po klasie komponentu):

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

Udało Ci się zaimplementować górny komponent React na pasku aplikacji. Jeśli przejdziesz na stronę http://localhost:8080, możesz wypróbować stronę demonstracyjną. Strona demonstracyjna będzie działać tak samo jak strona demonstracyjna MEDC Web. Strona demonstracyjna powinna wyglądać tak:

3D983b98c2092e7a.png

6. Podsumowanie

W tym samouczku pokazaliśmy, jak pakować zawartość biblioteki MDC Web Foundation do użytku w aplikacji React. W GitHub i npm znajduje się kilka bibliotek, które opakowują komponenty MDC Web Komponenty zgodnie z opisem w sekcji Integracja z platformami. Zalecamy skorzystanie z listy dostępnej tutaj. Ta lista zawiera też inne platformy, np. Angular czy Vue.

Ten samouczek przedstawia naszą decyzję o podzieleniu kodu MDC Web na 3 części: Podstawy, Adapter i Komponent. Taka architektura umożliwia komponentom współdzielenie wspólnego kodu przy pracy ze wszystkimi platformami. Dziękujemy za wypróbowanie Material Komponents React i zapoznaj się z naszą nową biblioteką MDC React. Mamy nadzieję, że to ćwiczenie z programowania Ci się podobało.

Udało mi się ukończyć to ćwiczenia z programowania w rozsądny sposób i w rozsądny sposób

Całkowicie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Całkowicie się nie zgadzam

Chcę w przyszłości nadal używać komponentów Material Komponenty

Całkowicie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Całkowicie się nie zgadzam
.