estilo_por_componente - VWJavascript/Alurapic GitHub Wiki

Estilo por component

Agora, vamos editar alurapic/client/app/painel/painel.component.ts para incluir styleUrls:

// alurapic/client/app/painel/painel.component.ts

import { Component, Input, OnInit } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'painel',
    templateUrl: './painel.component.html',
    styleUrls: ['./painel.component.css']
})
export class PainelComponent implements OnInit {

    @Input() titulo: string;

    ngOnInit() {
        this.titulo = this.titulo.length > 7 ?
             this.titulo.substr(0, 7) + '...' : 
             this.titulo;
    }

}

E também alurapic/client/app/foto/foto.component.ts:

// alurapic/client/app/foto/foto.component.ts

import { Component, Input } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'foto',
    templateUrl: './foto.component.html',
    styleUrls: ['./foto.component.css'] 
})
export class FotoComponent {

    @Input() titulo: string = '';
    @Input() url: string = '';
    descricao: string = '';
    _id: string = '';
}

Veja que através da configuração styleUrls dos nossos componentes indicamos em um array todos os CSS's utilizados por eles, em nosso caso, apenas um arquivo. Depois de darmos um tempo para o TypeScript compilar nosso arquivo e recarregarmos a página, vemos que nosso painel continua funcionando.

A primeira forma dessa abordagem é que não precisamos lembrar de importar a folha de estilo do nosso componente. Simplesmente importamos o componente onde queremos utilizá-lo e todo seu estilo será carregado automaticamente. Em segundo lugar, não houve conflito de seletores, algo que conseguimos sem a necessidade de uma classe auxiliar. Mas como o Angular consegui esta última façanha?

Vamos inspecionar nossa página index.html no browser. Veja que a tag

da nossa página foram adicionadas duas tag's <style>, cada uma com o estilo dos nossos componentes:
/* o código a seguir é o head no DOM sendo inspecionado no browser, não entra em nenhum lugar no código da nossa aplicação  */
<stye>
.efeito[_ngcontent-irr-5] {
    box-shadow: 2px 2px 15px;
}
</style>
.efeito[_ngcontent-gwo-4]:hover {
    transition: all 0.5s;
    transform: scale(1.15);
}
.efeito[_ngcontent-gwo-4] {
    transition: all 1s;
}

Um ponto curioso é que o Angular simplesmente não copiou e colou o estilo dos nossos arquivos, ele também alterou os seletores que usamos! Veja que foi adicionado para cada seletor um seletor de atributo, porém um atributo um tanto estranho. Este atributo é gerado aleatoriamente e adicionado em cada uma dos nossos componentes no DOM pelo Angular.

Por exemplo, se tivermos cinco Foto, todos terão o mesmo atributo porque são o mesmo componente, se tivermos outro componente ele terá seu próprio atributo. Com essa alteração, temos certeza que o estilo será aplicado apenas ao tipo de componente para o qual foi criado. Vejamos o elemento que representa nosso painel no DOM e seu atributo:

/* o código a seguir é o head no DOM sendo inspecionado, não entra em nenhum lugar no código da nossa aplicação  */
<div _ngcontent-irr-5 class="panel panel-default efeito">

ViewEncapsulation e seus tipos

O que acabamos de ver é a estratégia padrão de encapsulamento de view do Angular, a estratégia ViewEncapsulation.Emulated . Podemos até explicitar essa estratégia em nosso código alterando nosso componente de painel:

// alurapic/client/app/foto/foto.component.ts 

import { Component, Input, ViewEncapsulation } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'foto',
    templateUrl: './foto.component.html',
    styleUrls: ['./foto.component.css'],
    encapsulation: ViewEncapsulation.Emulated
})
export class FotoComponent {

    @Input() titulo: string = '';
    @Input() url: string = '';
    descricao: string = '';
    _id: string = '';
}

A palavra Emulated significa emulado. Quem emula, emula alguma coisa, certo? O alvo da emulação é o Shadow DOM.

Shadow DOM, podemos confiar?

Shadow DOM é recurso dos Web Components, uma tecnologia emergente proposta pela Google à W3C que permite encapsular Javascript, CSS e template em um componente. Apesar do Shadow DOM já existir antes dos Web Componentes, não podíamos manipulá-lo. Um exemplo disso é o uso do do HTML5. Você nunca se perguntou em que lugar fica definida marcação, o estilo e o comportamento do calendário que é exibido?

Perceba que o Shadow DOM oferece justamente o que acabamos de atingir: encapsular nosso estilo em nosso componente. Porém, nem todo navegador suporta completamente todas as características de um Web Component e por conseguinte a possibilidade de manipular ou criar o Shadow DOM de um elemento, é por isso que o Angular emula esta funcionalidade alterando nossos seletores e adicionando atributos aleatórios que não se repetem.

No entanto, se você estiver usando Chrome pode ativar o modo nativo. Vamos fazer um teste?

// alurapic/client/app/foto/foto.component.ts 

import { Component, Input, ViewEncapsulation } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'foto',
    templateUrl: './foto.component.html',
    styleUrls: ['./foto.component.css'],
    encapsulation: ViewEncapsulation.Native
})
export class FotoComponent {

    @Input() titulo: string = '';
    @Input() url: string = '';
    descricao: string = '';
    _id: string = '';
}

Veja que nosso layout deixa de funcionar. Qual motivo? Quando habilitarmos o modo nativo, o componente só terá acesso àqueles CSS's que foram explicitados no atributo styleUrls. Veja que nosso componente depende do bootstrap e não conseguiu enxergá-lo. Se quisermos que nosso componente enxergue o Bootstrap precisaremos adicioná-lo na lista de estilos de que depende.

Na versão emulada, o problema da aplicabilidade única por componente é resolvida, mas o elemento ainda consegue acessar estilos globais fora do seu escopo como os definidos pelo bootstrap. Para nosso projeto, a versão emulada nos é conveniente, mas o ideal era termos cada componente do bootstrap em um estilo em separado para em seguida importarmos cada um desses estilos em nosso componente.

Por fim, existe ViewEncapsulation.None, que apenas "joga" os estilos para dentro da tag head usando a tag style, mas sem qualquer preocupação em garantir que esses estilos sejam aplicados nos componentes para os mais foram criados. Acabamos caindo no mesmo problema do início do capítulo.

Sendo assim, vamos manter ViewEncapsulation.Emulated. Mesmo sendo o padrão, vou explicitar essa configuração em cada um de nossos componentes. Vai que a Google muda esse padrão no futuro, certo?

⚠️ **GitHub.com Fallback** ⚠️