1. Wprowadzenie
Komponenty Material Design (MDC) pomagają deweloperom wdrażać Material Design. MDC to biblioteka stworzona przez zespół inżynierów i projektantów UX w Google. Zawiera dziesiątki pięknych i funkcjonalnych komponentów UI. Jest dostępna na Androida, iOS, web i Flutter.material.io/develop |
MDC Web jest zaprojektowany tak, aby można było go zintegrować z dowolnym front-end frameworkem, zachowując jednocześnie zasady Material Design. Z tego ćwiczenia w Codelab dowiesz się, jak tworzyć komponenty React, które korzystają z MDC Web jako podstawy. Zasady omówione w tym ćwiczeniu z programowania można zastosować w dowolnej platformie JavaScript.
Jak zbudować 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.
Fundamenty zawierają logikę biznesową, która implementuje styl Material Design. Fundacja nie odwołuje się do żadnych elementów HTML. Pozwala to nam przedstawić abstrakcyjną logikę interakcji HTML do Adaptera. Fundamenty mają adapter.
Przejściówka to interfejs. Interfejs adaptera jest używany przez fundamenty do implementowania logiki biznesowej Material Design. Adapter możesz zaimplementować w różnych platformach, np. Angular lub React. Implementacja adaptera wchodzi w interakcje ze strukturą DOM.
Komponent ma fundament, a jego rola polega na
- Zaimplementuj adapter, używając kodu JavaScript bez frameworka, i
- Udostępnianie publicznych metod, które są proxy do metod w Foundation.
Co oferuje MDC Web
Każdy pakiet w MDC Web ma komponent, podstawę i adapter. Aby utworzyć instancję Component, musisz przekazać do metody konstruktora obiektu element element główny. Komponent implementuje adapter, który współpracuje z elementami DOM i HTML. Następnie Komponent tworzy instancję Foundation, która wywołuje metody Adapter.
Aby zintegrować MDC Web z ramami, musisz utworzyć własny element w języku lub składni tego frameworku. Komponent platformy implementuje adapter MDC Web i korzysta z fundamentów MDC Web.
Co utworzysz
To ćwiczenie w Codelab pokazuje, jak utworzyć niestandardowy adapter, aby używać logiki Foundation w komponencie React w ramach Material Design. Obejmuje ona zaawansowane tematy omawiane w artykule Integracja z ramami. 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 tym ćwiczeniu z programowania utworzysz górny pasek aplikacji i ponownie utworzysz stronę demonstracyjną górnego paska aplikacji. Układ strony demonstracyjnej jest już skonfigurowany, więc możesz zacząć pracować nad górnym paskiem aplikacji. Górny pasek aplikacji będzie zawierać:
- Ikona nawigacji
- Działania
- Dostępne są 4 warianty: krótka, zawsze złożona, stała i wyraźna.
Co będzie Ci potrzebne:
- najnowszą wersję Node.js (w pakiecie z npm, menedżerem pakietów JavaScript),
- Przykładowy kod (który należy pobrać w następnym kroku)
- podstawy HTML, CSS, JavaScript i React;
Jak oceniasz swój poziom doświadczenia w programowaniu stron internetowych?
2. Konfigurowanie środowiska programistycznego
Pobierz aplikację Codelab dla początkujących
Aplikacja startowa znajduje się w katalogu material-components-web-codelabs-master/mdc-112/starter
.
...lub sklonuj 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:
Uruchomienie aplikacji startowej
W tym samym katalogu uruchom:
npm start
Rozpocznie się webpack-dev-server
. Aby wyświetlić stronę, otwórz w przeglądarce adres http://localhost:8080/.
Gotowe! W przeglądarce powinien być uruchomiony kod startowy strony demonstracyjnej paska aplikacji w ramach React. Powinieneś/powinnaś zobaczyć ścianę tekstu lorem ipsum, pole Ustawienia (w prawym dolnym rogu) oraz nieukończony pasek aplikacji u góry:
Rzuć okiem na kod i projekt
Jeśli otworzysz edytor kodu, katalog projektu powinien wyglądać mniej więcej tak:
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>
);
}
To punkt wejścia do funkcji 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 React metoda render
generuje kod HTML komponentu. Komponent górnego paska aplikacji będzie renderować tag <header />
i będzie się składać z 2 głównych sekcji:
- Ikona nawigacji i sekcja tytułu
- Sekcja ikon działań
Jeśli masz pytania na temat elementów w pasku aplikacji, zapoznaj się z dokumentacją na GitHub.
Zmień metodę render()
w funkcji TopAppBar.js
tak, 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 section. Pierwszy 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>
);
}
Deweloper importuje TopAppBar
do aplikacji React i przekazuje ikony działań do elementu TopAppBar
. Przykładowy kod inicjujący TopAppBar
znajdziesz w pliku App.js
.
Brakuje 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 też parametru this.classes
, ale zostanie on omówiony w późniejszej sekcji. Oprócz brakującej metody gettera this.classes
są jeszcze elementy TopAppBar
, które musisz zaimplementować, aby pasek aplikacji na górze mógł się prawidłowo renderować.
Na górnym pasku aplikacji brakuje jeszcze tych elementów komponentu React:
- Zainicjowana podstawa
- Metody adaptera do przekazania do podstawy
- znaczniki JSX,
- Zarządzanie wariantami (stałe, krótkie, zawsze zwinięty, widoczne)
Realizacja
- Zaimplementuj metody Adapter.
- Zainicjuj Foundation w tabeli
componentDidMount
. - W metodzie
componentWillUnmount
wywołaj metodę Foundation.destroy. - Skonfiguruj zarządzanie wariantami za pomocą metody pobierania, która łączy odpowiednie nazwy klas.
4. Implementowanie metod adaptera
Komponent JS bez ramki TopAppBar
implementuje te metody Adaptera (szczegóły znajdziesz tutaj):
hasClass()
addClass()
removeClass()
registerNavigationIconInteractionHandler()
deregisterNavigationIconInteractionHandler()
notifyNavigationIconClicked()
setStyle()
getTopAppBarHeight()
registerScrollHandler()
deregisterScrollHandler()
registerResizeHandler()
deregisterResizeHandler()
getViewportScrollY()
getTotalActionItems()
React ma zdarzenia syntetyczne oraz inne sprawdzone metody i wzorce kodowania, dlatego metody Adapter trzeba ponownie zaimplementować.
Metoda Getter adaptera
W pliku TopAppBar.js
dodaj do TopAppBar
tę metodę 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,
};
}
Interfejsy API adaptera do rejestrowania zdarzeń przewijania i zmiany rozmiaru są implementowane tak samo jak w wersji JS bez ramki, ponieważ React nie ma żadnego zdarzenia syntetycznego do przewijania ani zmiany rozmiaru i odwołuje się do natywnego systemu zdarzeń DOM. Funkcja getViewPortScrollY
musi też korzystać z natywnego modelu DOM, ponieważ jest to funkcja obiektu window
, który nie jest dostępny w interfejsie API React. Implementacje adapterów będą się różnić w zależności od frameworka.
Możesz zauważyć, że brakuje metody this.setStyle
, która jest wywoływana 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ą się pojawiać błędy, ponieważ implementacja nie została jeszcze w pełni ukończona. W następnej sekcji dowiesz się, jak dodawać i usuwać klasy CSS.
5. Implementowanie 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 pliku TopAppBar
znajdują się 3 fragmenty kodu, które współpracują z klasami CSS:
- komponent
<TopAppBar />
za pomocą właściwościclassName
. - Metoda Adapter za pomocą
addClass
lubremoveClass
. - Sztywny kod w komponencie React
<TopAppBar />
.
Najpierw dodaj ten import u góry pliku TopAppBar.js
, pod dotychczasowymi instrukcjami importu:
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 adres http://localhost:8080, pola wyboru sterowania powinny włączać i wyłączać nazwy klas w DOM.
Ten kod umożliwia wielu deweloperom korzystanie z funkcji TopAppBar
. Deweloperzy mogą korzystać z interfejsu API TopAppBar
, nie martwiąc się o szczegóły implementacji klas CSS.
Adapter został zaimplementowany. W następnej sekcji znajdziesz instrukcje tworzenia instancji Foundation.
Montowanie i odmontowywanie komponentu
Tworzenie instancji Foundation odbywa się w metodzie componentDidMount
.
Najpierw zaimportuj podstawy paska aplikacji MDC, dodając poniższy import po istniejących importach w pliku TopAppBar.js
:
import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';
Następnie dodaj do klasy TopAppBar
ten kod JavaScriptu:
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 praktyk kodowania w React jest definiowanie propTypes i defaultProps. Dodaj poniższy import po istniejących importach w pliku TopAppBar.js:
import PropTypes from 'prop-types';
Następnie dodaj ten kod na dole pliku TopAppBar.js
(po klasie 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,
};
Udało Ci się zaimplementować górny komponent React na pasku aplikacji. Jeśli otworzysz adres http://localhost:8080, możesz zapoznać się ze stroną demonstracyjną. Strona demonstracyjna będzie działać tak samo jak strona demonstracyjna MDC Web. Strona demonstracyjna powinna wyglądać tak:
6. Podsumowanie
W tym samouczku omówiliśmy, jak opakować komponent Foundation z MDC Web do użycia w aplikacji React. Na GitHubie i w npm jest kilka bibliotek, które otaczają komponenty MDC Web Components, jak opisano w sekcji Integracja z ramkami. Zalecamy korzystanie z listy dostępnej tutaj. Ta lista zawiera też inne platformy, np. Angular czy Vue.
W tym samouczku opisujemy naszą decyzję o podziale kodu MDC Web na 3 części: Foundation, Adapter i Component. Ta architektura umożliwia komponentom udostępnianie wspólnego kodu podczas 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.