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 |
O MDC Web foi projetado para ser integrado a 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 o MDC Web como base. Os princípios aprendidos neste codelab podem ser aplicados a qualquer framework JavaScript.
Como o MDC Web é criado
A camada JavaScript do MDC Web é composta por três classes por componente: Component, Foundation e Adapter. Esse padrão dá ao MDC Web a flexibilidade de integração com frameworks de front-end.
A Foundation contém a lógica de negócios que implementa o Material Design. A Fundação não faz referência a nenhum elemento HTML. Isso nos permite abstrair a lógica de interação do HTML no Adaptador. A Foundation tem um adaptador.
O Adaptador é uma interface. A interface do adaptador é referenciada pela Foundation para implementar a lógica de negócios do Material Design. É possível implementar o Adaptador 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 adaptador usando JavaScript sem framework e
- Fornecer métodos públicos que representem métodos na Fundação.
O que os MDC Web oferece
Todos os pacotes do MDC Web vêm com um componente, uma estrutura 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. O Componente instancia a Foundation, que chama os métodos do Adaptador.
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 a Foundation do MDC Web.
O que você vai criar
Este codelab demonstra como criar um Adaptador personalizado para usar a lógica do Foundation e criar um componente do React do Material Design. Ele aborda os tópicos avançados em Como integrar a frameworks. O React é usado neste codelab como um exemplo de framework, 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 da barra de apps superior. O layout da página de demonstração já está configurado para que você possa começar a trabalhar na barra de apps na parte de cima. A barra de apps superior inclui:
- Ícone de navegação
- Ações necessárias
- Há quatro variantes disponíveis: Curta, Sempre recolhida, Fixa e Proeminente.
O que você vai precisar:
- Uma versão recente do Node.js (que vem junto com o npm, um gerenciador de pacotes JavaScript)
- O exemplo de código (que será feito o download 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ê vai notar muita atividade e, no final, o terminal vai mostrar uma instalação bem-sucedida:
Executar o app inicial
No mesmo diretório, execute:
npm start
A webpack-dev-server
será iniciada. Acesse http://localhost:8080/ no navegador para conferir a página.
Pronto. O código inicial da página de demonstração da barra de apps superior do React precisa estar em execução no seu navegador. Você verá uma parede com o texto lorem ipsum, uma caixa Controles (canto inferior direito) e uma barra de apps superior inacabada:
Confira o código e o projeto
Se você abrir o editor de código, o diretório do projeto vai ficar assim:
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 o TopAppBar
no aplicativo.
Abra o arquivo TopAppBar.js
, que é uma classe Component
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 da barra de apps superior renderiza uma tag <header />
e é composto por duas seções principais:
- Seção de ícone de navegação e 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 de navegação e um título. O segundo 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
no aplicativo React e transmitir ícones de ação para o elemento TopAppBar
. Confira um exemplo de código inicializando um 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 não está no método render
, mas 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 ausentes 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 Adapter.
- Inicialize a Foundation no
componentDidMount
. - Chame o método Foundation.destroy no
componentWillUnmount
. - Estabeleça o gerenciamento de variantes usando um método getter que combine os nomes de classe apropriados.
4. Implementar métodos do adaptador
O componente TopAppBar
do JS sem 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, os métodos Adapter precisam ser implementados novamente.
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 do adaptador para registro de eventos de rolagem e redimensionamento são implementadas de forma idêntica à versão do JS sem framework, porque o React não tem nenhum evento sintético para rolagem ou redimensionamento e adia para o sistema de eventos DOM nativo. O getViewPortScrollY
também precisa ser adiado para o DOM nativo, já que é uma função no objeto window
, que não está na API do React. As implementações de adaptador serão diferentes para cada framework.
O this.setStyle
está ausente, o 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 Adaptador. Talvez você encontre erros no console, porque a implementação completa ainda não foi concluída. A próxima seção vai mostrar como adicionar e remover classes CSS.
5. Implementar métodos de 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 de classes CSS do JavaScript nativo, adicione a variável de estado classList
. Há três partes do código em TopAppBar
que interagem com as classes CSS:
- Componente
<TopAppBar />
usando a propriedadeclassName
. - O método Adapter usando
addClass
ouremoveClass
. - Programado no componente
<TopAppBar />
do React.
Primeiro, adicione a seguinte importação na parte de cima de TopAppBar.js
, abaixo das importações existentes:
import classnames from 'classnames';
Em seguida, adicione o seguinte código à 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.
Agora você já implementou o adaptador. Na próxima seção, vamos mostrar como instanciar uma Foundation.
Como montar e desconectar o componente
A instanciação da Foundation 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 existentes 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 importação a seguir 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. Se você acessar http://localhost:8080, poderá brincar com a página de demonstração. A página de demonstração vai funcionar da mesma forma que a página de demonstração da MDC Web. A página de demonstração vai ficar assim:
6. Conclusão
Neste tutorial, vimos como unir o Foundation do MDC Web para uso em um aplicativo React. Há algumas bibliotecas no Github e no npm que envolvem os componentes da Web do MDC, conforme descrito em Integração em frameworks. Recomendamos que você use a lista disponível 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 o código comum ao trabalhar com todos os frameworks. Agradecemos por testar o Material Components React. Confira nossa nova biblioteca MDC React. Esperamos que tenha gostado deste codelab.