1. Introdução
Os componentes do Material Design (MDC, na sigla em inglês) ajudam os desenvolvedores a implementar o Material Design. Criados por uma equipe de engenheiros e designers de UX do Google, os MDC apresentam dezenas de componentes de interface bonitos e funcionais e estão disponíveis para Android, iOS, Web e Flutter.material.io/develop |
Os MDC Web foram projetados para integrar-se em qualquer framework de front-end, mantendo os princípios do Material Design. O codelab a seguir orienta você na criação de um componente React, que usa a Web MDC como base. Os princípios aprendidos neste codelab podem ser aplicados a qualquer framework JavaScript.
Como a Web dos MDC é criada
A camada JavaScript do MDC Web é composta por três classes por componente: Component, Foundation e Adapter. Esse padrão dá aos MDC Web a flexibilidade para se integrar com frameworks de front-end.
A Fundação contém a lógica de negócios que implementa o Material Design. A base não faz referência a nenhum elemento HTML. Isso nos permite abstrair a lógica de interação HTML no Adapter. O elemento Foundation tem um Adapter.
O Adapter é uma interface. A interface Adapter é referenciada pela Foundation (link em inglês) para implementar a lógica de negócios do Material Design. Você pode implementar o Adapter em diferentes frameworks, como Angular ou React. Uma implementação de um adaptador interage com a estrutura do DOM.
O Componente tem uma fundação e a função dele é
- Implemente o Adapter usando um JavaScript sem framework.
- Fornecer métodos públicos que representem métodos na Fundação.
O que os MDC Web oferece
Todos os pacotes no MDC Web vêm com um componente, uma fundação e um adaptador. Para instanciar um Component, transmita o element raiz ao método construtor do componente. O Component implementa um Adapter, que interage com os elementos DOM e HTML. Em seguida, o Component instancia o Foundation, que chama os métodos do Adapter.
Para integrar os MDC Web a um framework, você precisa criar seu próprio componente na linguagem/sintaxe desse framework. O Component do framework implementa o Adapter do MDC Web e usa o Foundation do MDC Web.
O que você vai criar
Este codelab demonstra como criar um adaptador personalizado para usar a lógica Foundation e criar um componente React do Material Design. Ele aborda os tópicos avançados em Como integrar a frameworks. Neste codelab, o React é usado como um framework de exemplo, mas essa abordagem pode ser aplicada a qualquer outro framework.
Neste codelab, você vai criar a barra de apps superior e recriar a página de demonstração dela. O layout da página de demonstração já está configurado, então você pode começar a trabalhar na barra de apps superior. A barra de apps superior inclui o seguinte:
- Ícone de navegação
- Ações necessárias
- Há quatro variantes disponíveis: Short, sempre recolhida, fixa e em destaque
O que é necessário:
- Uma versão recente do Node.js (que acompanha o NPM, um gerenciador de pacotes JavaScript)
- O exemplo de código (que será feito na próxima etapa)
- Conhecimento básico de HTML, CSS, JavaScript e React.
Como você classificaria seu nível de experiência com desenvolvimento da Web?
2. Configurar o ambiente de desenvolvimento
Faça o download do app inicial do codelab
O app inicial está localizado no diretório material-components-web-codelabs-master/mdc-112/starter
.
... ou clone-o do GitHub
Para clonar este codelab do GitHub, execute estes comandos:
git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-112/starter
Instalar dependências do projeto
No diretório inicial material-components-web-codelabs/mdc-112/starter
, execute:
npm install
Você verá muitas atividades e, no final, o terminal mostrará uma instalação bem-sucedida:
Executar o app inicial
No mesmo diretório, execute:
npm start
A webpack-dev-server
será iniciada. No navegador, acesse http://localhost:8080/ para ver a página.
Pronto. O código inicial da página de demonstração do Top App Bar React será executado no navegador. Você verá uma parede com o texto lorem ipsum, uma caixa Controles (canto inferior direito) e uma barra de apps superior inacabada:
Conferir o código e o projeto
Se você abrir o editor de código, o diretório do projeto terá esta aparência:
Abra o arquivo App.js
e observe o método render
, que inclui o componente <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>
);
}
Esse é o ponto de entrada para TopAppBar
no aplicativo.
Abra o arquivo TopAppBar.js
, que é uma classe Component
do React simples com um método render
:
TopAppBar.js
import React from 'react';
export default class TopAppBar extends React.Component {
render() {
return (
<header>
TOP APP BAR
</header>
);
}
}
3. Composição do componente
No React, o método render
gera o HTML do componente. O componente "Barra de apps superior" renderiza uma tag <header />
e é composto por duas seções principais:
- Ícone de navegação e seção de título
- Seção de ícones de ação
Se você tiver dúvidas sobre os elementos que compõem a barra de apps superior, acesse a documentação no GitHub.
Modifique o método render()
em TopAppBar.js
para que fique assim:
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>
);
}
Há dois elementos de seção neste HTML. A primeira contém um ícone e um título de navegação. A segunda contém ícones de ação.
Em seguida, adicione o método 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>
);
}
Um desenvolvedor vai importar TopAppBar
para o aplicativo React e transmitir ícones de ação para o elemento TopAppBar
. Confira um exemplo de código inicializando TopAppBar
em App.js
.
O método getMergedStyles
está ausente e é usado no método render
. Adicione o seguinte método JavaScript à classe TopAppBar
:
getMergedStyles = () => {
const {style} = this.props;
const {style: internalStyle} = this.state;
return Object.assign({}, internalStyle, style);
}
O this.classes
também está ausente no método render
, mas isso será abordado em uma seção posterior. Além do método getter ausente, this.classes
, ainda há partes do TopAppBar
que você precisa implementar para que a barra de apps superior possa ser renderizada corretamente.
As partes do componente React que ainda estão faltando na barra de apps superior são:
- Uma base inicializada
- Métodos do adaptador a serem transmitidos para a base
- Marcação JSX
- Gerenciamento de variantes (fixo, curto, sempre recolhido, em destaque)
A abordagem
- Implemente os métodos do Adapter.
- Inicialize a Foundation no
componentDidMount
. - Chame o método Foundation.destroy no
componentWillUnmount
. - Estabeleça o gerenciamento de variantes com um método getter que combina os nomes de classe apropriados.
4. Implementar métodos do adaptador
O componente JS TopAppBar
que não é framework implementa os seguintes métodos de adaptador (listados em detalhes aqui):
hasClass()
addClass()
removeClass()
registerNavigationIconInteractionHandler()
deregisterNavigationIconInteractionHandler()
notifyNavigationIconClicked()
setStyle()
getTopAppBarHeight()
registerScrollHandler()
deregisterScrollHandler()
registerResizeHandler()
deregisterResizeHandler()
getViewportScrollY()
getTotalActionItems()
Como o React tem eventos sintéticos e diferentes práticas e padrões de programação recomendados, os métodos Adapter precisam ser reimplementados.
Método getter do adaptador
No arquivo TopAppBar.js
, adicione o seguinte método JavaScript a 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,
};
}
As APIs de adaptador para registro de eventos de rolagem e redimensionamento são implementadas de forma idêntica à versão JS sem framework, porque o React não tem nenhum evento sintético para rolagem ou redimensionamento e adere ao sistema de eventos DOM nativo. O getViewPortScrollY
também precisa respeitar o DOM nativo, já que é uma função no objeto window
, que não está na API React. As implementações de adaptadores serão diferentes para cada framework.
Você pode notar que o this.setStyle
está ausente, que é chamado pelo método get adapter
. No arquivo TopAppBar.js
, adicione o método JavaScript ausente à classe TopAppBar
:
setStyle = (varName, value) => {
const updatedStyle = Object.assign({}, this.state.style);
updatedStyle[varName] = value;
this.setState({style: updatedStyle});
}
Você acabou de implementar o Adapter. Talvez você veja erros no seu console neste momento porque a implementação completa ainda não está concluída. Na próxima seção, vamos mostrar como adicionar e remover classes CSS.
5. Implementar métodos dos componentes
Como gerenciar variantes e classes
O React não tem uma API para gerenciar classes. Para imitar os métodos de adição/remoção da classe CSS do JavaScript nativo, adicione a variável de estado classList
. Há três partes de código em TopAppBar
que interagem com classes CSS:
- Componente
<TopAppBar />
usando a propriedadeclassName
. - O método Adapter via
addClass
ouremoveClass
. - Codificado no componente
<TopAppBar />
do React.
Primeiro, adicione a importação abaixo na parte de cima de TopAppBar.js
, abaixo das importações atuais:
import classnames from 'classnames';
Em seguida, adicione o código abaixo na declaração de classe do componente 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,
});
}
...
}
Se você acessar http://localhost:8080, as caixas de seleção dos controles devem ativar/desativar os nomes de classes do DOM.
Esse código torna o TopAppBar
utilizável por muitos desenvolvedores. Os desenvolvedores podem interagir com a API TopAppBar
sem se preocupar com os detalhes de implementação das classes CSS.
Você implementou o Adapter com sucesso. Na próxima seção, vamos mostrar como instanciar uma Foundation.
Como montar e desconectar o componente
A instanciação da base acontece no método componentDidMount
.
Primeiro, importe as bases da barra de apps superior do MDC adicionando a seguinte importação após as importações atuais em TopAppBar.js
:
import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';
Em seguida, adicione o seguinte código JavaScript à classe 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();
}
...
}
Uma boa prática de programação do React é definir propTypes e defaultProps. Adicione a seguinte importação após as importações atuais em TopAppBar.js:
import PropTypes from 'prop-types';
Em seguida, adicione o seguinte código à parte de baixo de TopAppBar.js
, depois da classe 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,
};
Você implementou o componente de reação da barra de apps superior. Acesse http://localhost:8080 para acessar a página de demonstração. A página de demonstração funcionará da mesma forma que a página de demonstração da Web do MDC. A página de demonstração vai ficar assim:
6. Resumo
Neste tutorial, abordamos como unir o Foundation do MDC Web para uso em um aplicativo React. Existem algumas bibliotecas no GitHub e no npm que unem os MDC Web Components, conforme descrito em Como integrar a frameworks. Recomendamos que você use a lista aqui. Essa lista também inclui outros frameworks além do React, como Angular e Vue.
Este tutorial destaca nossa decisão de dividir o código da Web MDC em três partes: fundação, adaptador e componente. Essa arquitetura permite que os componentes compartilhem código comum enquanto trabalham com todos os frameworks. Agradecemos por testar o Material Components React. Confira nossa nova biblioteca, MDC React. Esperamos que tenha gostado deste codelab.