MDC-112 Web: интеграция MDC с веб-платформами

MDC-112 Web:
интеграция MDC с веб-платформами

О практической работе

subjectПоследнее обновление: окт. 11, 2020
account_circleАвторы: Liz Mitchell, Abhinay Omkar

1. Введение

logo_comComponents_color_2x_web_96dp.png

Material Components (MDC) помогают разработчикам реализовать Material Design. Созданный командой инженеров и UX-дизайнеров Google, MDC включает в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступен для Android, iOS, Интернета и Flutter.material.io/develop.

MDC Web спроектирован для интеграции в любую интерфейсную среду, сохраняя при этом принципы Material Design. Следующая лаборатория кода поможет вам создать компонент React, который использует MDC Web в качестве основы. Принципы, изученные в этой лаборатории кода, можно применить к любой среде JavaScript.

Как устроен MDC Web

Уровень JavaScript MDC Web состоит из трех классов для каждого компонента: Component , Foundation и Adaptor . Этот шаблон дает MDC Web гибкость для интеграции с интерфейсными платформами.

Foundation содержит бизнес-логику, реализующую Material Design. Фонд не ссылается ни на какие элементы HTML. Это позволяет нам абстрагировать логику взаимодействия HTML в адаптер . У Foundation есть адаптер .

Адаптер — это интерфейс. Интерфейс адаптера используется Фондом для реализации бизнес-логики Material Design. Вы можете реализовать адаптер в различных средах, таких как Angular или React. Реализация адаптера взаимодействует со структурой DOM.

Компонент имеет основу , и его роль заключается в

  1. Реализуйте адаптер , используя нефреймворковый JavaScript, и
  2. Предоставьте общедоступные методы, которые проксируют методы Foundation .

Что предоставляет MDC Web

Каждый пакет в MDC Web поставляется с компонентом , основой и адаптером . Чтобы создать экземпляр компонента, вы должны передать корневой элемент методу конструктора компонента. Компонент реализует адаптер , который взаимодействует с элементами DOM и HTML. Затем Компонент создает экземпляр Foundation , который вызывает методы Адаптера .

Чтобы интегрировать MDC Web в платформу, вам необходимо создать собственный компонент на языке/синтаксисе этой платформы. Компонент платформы реализует адаптер MDC Web и использует MDC Web Foundation .

Что ты построишь

В этой лаборатории кода показано, как создать собственный адаптер для использования логики Foundation для создания компонента Material Design React. В нем рассматриваются сложные темы, представленные в разделе «Интеграция в платформы» . React используется в этой лаборатории кода в качестве примера платформы, но этот подход можно применить к любой другой платформе.

В этой лаборатории кода вы создадите верхнюю панель приложений и воссоздадите демонстрационную страницу верхней панели приложений. Макет демонстрационной страницы уже настроен, поэтому вы можете начать работу с верхней панелью приложений. Верхняя панель приложений будет включать в себя:

  • Значок навигации
  • Действия
  • Доступно 4 варианта: короткий , всегда свернутый , фиксированный и заметный .

Что вам понадобится:

  • Последняя версия Node.js (которая поставляется в комплекте с npm , менеджером пакетов JavaScript).
  • Пример кода (можно загрузить на следующем шаге)
  • Базовые знания HTML, CSS, JavaScript и React.

Как бы вы оценили свой уровень опыта веб-разработки?

2. Настройка среды разработки

Загрузите начальное приложение Codelab.

Стартовое приложение находится в каталоге material-components-web-codelabs-master/mdc-112/starter .

...или клонируйте его с GitHub

Чтобы клонировать эту кодовую лабораторию из GitHub, выполните следующие команды:

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

Установить зависимости проекта

Из стартового каталогаmaterial material-components-web-codelabs/mdc-112/starter запустите:

npm install

Вы увидите много активности, и в конце ваш терминал должен показать успешную установку:

22a33efc2a687408.png

Запустите стартовое приложение

В том же каталоге запустите:

npm start

webpack-dev-server запустится. Направьте свой браузер на http://localhost:8080/, чтобы увидеть страницу.

b55c66dd400cf34f.png

Успех! Стартовый код для демонстрационной страницы Top App Bar React должен быть запущен в вашем браузере. Вы должны увидеть стену текста lorem ipsum , поле управления (внизу справа) и незаконченную верхнюю панель приложений:

4ca3cf6d216f9290.png

Взгляните на код и проект

Если вы откроете редактор кода, каталог проекта должен выглядеть примерно так:

e9a3270d6a67c589.png

Откройте файл App.js и посмотрите на метод render , который включает компонент <TopAppBar> :

Приложение.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>
    );
  }

Это точка входа для TopAppBar в приложении.

Откройте файл TopAppBar.js , который представляет собой простой класс Component React с методом render :

ТопAppBar.js

import React from 'react';

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

3. Состав компонента

В React метод render выводит HTML-код компонента. Компонент Top App Bar отображает тег <header /> и состоит из двух основных разделов:

  1. Значок навигации и заголовок раздела
  2. Раздел значков действий

Если у вас есть вопросы об элементах, составляющих верхнюю панель приложений, посетите документацию на GitHub .

Измените метод render() в TopAppBar.js , чтобы он выглядел следующим образом:

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

В этом HTML есть два элемента раздела. Первый содержит значок навигации и заголовок. Второй содержит значки действий.

Затем добавьте метод 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>
  );
}

Разработчик импортирует TopAppBar в свое приложение React и передаст значки действий в элемент TopAppBar . Вы можете увидеть пример кода, инициализирующего TopAppBar в App.js

Отсутствует метод getMergedStyles , который используется в методе render . Добавьте следующий метод JavaScript в класс TopAppBar :

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

this.classes также отсутствует в методе render , но будет рассмотрен в следующем разделе. Помимо отсутствующего метода получения this.classes , есть еще части TopAppBar , которые необходимо реализовать, прежде чем верхняя панель приложений сможет правильно отображаться.

Части компонента React, которые все еще отсутствуют в верхней панели приложений:

  • Инициализированный фундамент
  • Методы адаптера для перехода в фундамент
  • JSX-разметка
  • Вариант управления (фиксированный, короткий, всегда свернутый, заметный)

Подход

  1. Реализуйте методы адаптера .
  2. Инициализируйте Foundation в componentDidMount .
  3. Вызовите метод Foundation.destroy в componentWillUnmount .
  4. Установите управление вариантами с помощью метода получения, который объединяет соответствующие имена классов.

4. Реализация методов адаптера

Нефреймворковый JS TopAppBar Component реализует следующие методы адаптера (подробно перечислены здесь ):

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

Поскольку в React есть синтетические события и различные лучшие практики и шаблоны кодирования, методы адаптера необходимо переопределить.

Метод получения адаптера

В файле TopAppBar.js добавьте в TopAppBar следующий метод JavaScript:

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

API-интерфейсы адаптера для регистрации событий прокрутки и изменения размера реализованы идентично версии JS без платформы, поскольку React не имеет синтетических событий для прокрутки или изменения размера и подчиняется собственной системе событий DOM. getViewPortScrollY также необходимо использовать собственный DOM, поскольку это функция объекта window , которой нет в API React. Реализации адаптера будут разными для каждой платформы.

Вы можете заметить, что отсутствует this.setStyle , который вызывается методом get adapter . В файле TopAppBar.js добавьте недостающий метод JavaScript в класс TopAppBar :

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

Вы только что реализовали адаптер ! Обратите внимание, что на этом этапе вы можете увидеть ошибки в консоли, поскольку полная реализация еще не завершена. В следующем разделе вы узнаете, как добавлять и удалять классы CSS.

5. Реализация методов компонента

Управление вариантами и классами

У React нет API для управления классами. Чтобы имитировать собственные методы добавления/удаления классов CSS в JavaScript, добавьте переменную состояния classList . В TopAppBar есть три фрагмента кода, которые взаимодействуют с классами CSS:

  1. Компонент <TopAppBar /> через свойство className .
  2. Метод адаптера через addClass или removeClass .
  3. Жестко запрограммировано в компоненте React <TopAppBar /> .

Сначала добавьте следующий импорт вверху TopAppBar.js под существующим импортом:

import classnames from 'classnames';

Затем добавьте следующий код в объявление класса компонента 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,
    });
  }

  ...
}

Если вы перейдете по адресу http://localhost:8080, флажки «Управление» теперь должны включать/выключать имена классов из DOM.

Этот код делает TopAppBar доступным для использования многими разработчиками. Разработчики могут взаимодействовать с API TopAppBar , не беспокоясь о деталях реализации классов CSS.

Теперь вы успешно внедрили адаптер. В следующем разделе вы узнаете, как создать экземпляр Foundation .

Монтаж и демонтаж компонента

Создание экземпляра Foundation происходит в методе componentDidMount .

Сначала импортируйте основы верхней панели приложений MDC, добавив следующий импорт после существующего импорта в TopAppBar.js :

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

Затем добавьте следующий код JavaScript в класс 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();
  }
 
  ...

}

Одна из хороших практик кодирования React — определение propTypes и defaultProps. Добавьте следующий импорт после существующего импорта в TopAppBar.js:

import PropTypes from 'prop-types';

Затем добавьте следующий код в конец TopAppBar.js (после класса 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,
};

Теперь вы успешно реализовали компонент React Top App Bar. Если вы перейдете по адресу http://localhost:8080, вы сможете поиграть с демонстрационной страницей. Демонстрационная страница будет работать так же, как и демонстрационная страница MDC Web . Демо-страница должна выглядеть так:

3d983b98c2092e7a.png

6. Заворачивать

В этом уроке мы рассмотрели, как обернуть MDC Web Foundation для использования в приложении React. На Github и npm есть несколько библиотек, которые обертывают веб-компоненты MDC, как описано в разделе «Интеграция в платформы» . Мы рекомендуем вам использовать список, найденный здесь . В этот список также входят другие фреймворки помимо React, такие как Angular и Vue.

В этом руководстве рассказывается о нашем решении разделить веб-код MDC на три части: основу , адаптер и компонент. Эта архитектура позволяет компонентам использовать общий код при работе со всеми платформами. Спасибо, что попробовали Material Components React. Пожалуйста, ознакомьтесь с нашей новой библиотекой MDC React . Мы надеемся, что вам понравилась эта кодовая лаборатория!

Мне удалось завершить эту кодовую работу, потратив разумное количество времени и усилий.

Я хотел бы продолжать использовать Material Components в будущем.