1. Введение
Компоненты Material (MDC) помогают разработчикам внедрять Material Design. Созданные командой инженеров и UX-дизайнеров Google, MDC включают в себя десятки красивых и функциональных компонентов пользовательского интерфейса и доступны для Android, iOS, веб-приложений и Flutter.material.io/develop |
MDC Web разработан для интеграции с любым фронтенд-фреймворком, при этом сохраняя принципы Material Design. В этом практическом занятии вы научитесь создавать компонент React, используя MDC Web в качестве основы. Принципы, изученные в этом занятии, могут быть применены к любому JavaScript-фреймворку.
Как создается веб-интерфейс MDC
JavaScript-слой MDC Web состоит из трех классов для каждого компонента: Component , Foundation и Adapter . Такая структура обеспечивает MDC Web гибкость интеграции с фронтенд-фреймворками.
В Foundation содержится бизнес-логика, реализующая Material Design. Foundation не ссылается ни на какие HTML-элементы. Это позволяет нам абстрагировать логику взаимодействия с HTML в Adapter . Foundation имеет Adapter .
Адаптер — это интерфейс. Фонд использует интерфейс «Адаптер» для реализации бизнес-логики Material Design. Вы можете реализовать адаптер в различных фреймворках, таких как Angular или React. Реализация адаптера взаимодействует со структурой DOM.
Компонент имеет фундамент , и его роль заключается в том, чтобы
- Реализуйте адаптер , используя JavaScript без привязки к фреймворку, и
- Предоставьте общедоступные методы, которые будут выступать в качестве прокси для методов в Фонде .
Что предоставляет MDC Web
Каждый пакет в MDC Web включает в себя Component , Foundation и Adapter . Для создания экземпляра Component необходимо передать корневой элемент в метод конструктора Component. Component реализует интерфейс Adapter , который взаимодействует с элементами DOM и HTML. Затем Component создает экземпляр Foundation , который вызывает методы Adapter .
Для интеграции MDC Web в фреймворк необходимо создать собственный компонент на языке/синтаксисе этого фреймворка. Компонент фреймворка реализует интерфейс Adapter MDC Web и использует Foundation MDC Web.
Что вы построите
В этом практическом занятии показано, как создать собственный адаптер для использования логики Foundation с целью создания компонента React в стиле Material Design. Рассматриваются продвинутые темы, описанные в разделе «Интеграция во фреймворки» . В качестве примера в этом занятии используется 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-components-web-codelabs/mdc-112/starter выполните:
npm install
Вы увидите много активности, и в конце в терминале должно отобразиться сообщение об успешной установке:

Запустите стартовое приложение
В той же директории выполните:
npm start
Запустится webpack-dev-server . Откройте в браузере страницу по адресу http://localhost:8080/ .

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

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

Откройте файл App.js и посмотрите на метод render , который включает компонент <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>
);
}
Это точка входа для панели TopAppBar в приложении.
Откройте файл TopAppBar.js , который представляет собой простой класс Component React с методом render :
TopAppBar.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 /> и будет состоять из двух основных разделов:
- Значок навигации и раздел заголовка
- Раздел значков действий
Если у вас возникли вопросы об элементах, составляющих верхнюю панель приложений, посетите документацию на 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-коде есть два элемента `section`. Первый содержит иконку навигации и заголовок. Второй содержит иконки действий.
Далее добавьте метод 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);
}
В методе render также отсутствует this.classes , но это будет рассмотрено в последующем разделе. Помимо отсутствующего метода getter, this.classes , есть еще несколько частей TopAppBar , которые необходимо реализовать, прежде чем Top App Bar сможет корректно отображаться.
В компоненте React, которого до сих пор не хватает в Top App Bar, следующие элементы:
- Первоначальный фундамент
- Способы подключения адаптеров для прокладки кабелей в фундамент.
- Разметка JSX
- Управление вариантами (фиксированный, короткий, всегда свернутый, выделенный)
Подход
- Реализуйте методы адаптера .
- Инициализируйте Foundation в методе
componentDidMount. - Вызовите метод Foundation.destroy в компоненте
componentWillUnmount. - Организуйте управление вариантами с помощью метода-геттера, который объединяет соответствующие имена классов.
4. Реализуйте методы адаптера.
Компонент TopAppBar на JavaScript, не использующий фреймворк, реализует следующие методы адаптера (подробно описаны здесь ):
-
hasClass() -
addClass() -
removeClass() -
registerNavigationIconInteractionHandler() -
deregisterNavigationIconInteractionHandler() -
notifyNavigationIconClicked() -
setStyle() -
getTopAppBarHeight() -
registerScrollHandler() -
deregisterScrollHandler() -
registerResizeHandler() -
deregisterResizeHandler() -
getViewportScrollY() -
getTotalActionItems()
Поскольку React использует синтетические события и различные лучшие практики и шаблоны кодирования, методы адаптера необходимо переписать.
Метод адаптерного геттера
В файл TopAppBar.js добавьте следующий метод JavaScript для 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,
};
}
API адаптера для регистрации событий прокрутки и изменения размера реализованы идентично версии JavaScript без использования фреймворков, поскольку 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-классами:
- Компонент
<TopAppBar />через свойствоclassName. - Метод адаптера через
addClassилиremoveClass. - Это жестко закодировано внутри компонента 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 Top App Bar, добавив следующий импорт после существующих импортов в 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,
};
Вы успешно реализовали компонент Top App Bar React. Перейдя по адресу http://localhost:8080, вы можете протестировать демонстрационную страницу. Демонстрационная страница будет работать так же, как и демонстрационная страница MDC Web . Демонстрационная страница должна выглядеть следующим образом:

6. Подведение итогов
В этом руководстве мы рассмотрели, как обернуть Foundation от MDC Web для использования в приложении React. На Github и npm есть несколько библиотек, которые оборачивают компоненты MDC Web, как описано в разделе «Интеграция во фреймворки» . Мы рекомендуем использовать список, который можно найти здесь . Этот список также включает другие фреймворки, помимо React, такие как Angular и Vue.
В этом руководстве мы рассказываем о нашем решении разделить код MDC Web на 3 части: Foundation , Adapter и Component. Такая архитектура позволяет компонентам совместно использовать общий код и работать со всеми фреймворками. Спасибо, что попробовали Material Components React, и, пожалуйста, ознакомьтесь с нашей новой библиотекой MDC React . Надеемся, вам понравился этот мастер-класс!