- Aprenda
-
Ecossistema
Ajuda
Ferramentas
Bibliotecas Oficias
Notícias
Listas de Recursos
- Equipe
- Patrocine
- Traduções
Guia
Essenciais
- Instalação
- Introdução
- A Instância Vue
- Sintaxe de Templates
- Dados Computados e Observadores
- Interligações de Classe e Estilo
- Renderização Condicional
- Renderização de Listas
- Manipulação de Eventos
- Interligações em Formulários
- Componentes
Components In-Depth
- Component Registration
- Props
- Custom Events
- Slots
- Dynamic & Async Components
- Handling Edge Cases
Transições & Animações
- Transições de Visibilidade e Listas
- Transições de Estado
Reuso & Composição
- Mixins
- Diretivas Personalizadas
- Funções de Renderização & JSX
- Plugins
- Filtros
Ferramentas
- Publicando em Produção
- Componentes Single-File
- Testes Unitários
- Suporte ao TypeScript
Escalonando
- Roteamento
- Gerenciamento de Estado
- Renderizando no Lado do Servidor
Internamente
- Reatividade em Profundidade
Migração
- Migração do Vue 1.x
- Migração do Vue Router 0.7.x
- Migração do Vuex 0.6.x para 1.0
Diversos
- Comparação com Outros Frameworks
- Junte-se à Comunidade Vue.js!
- Conheça a Equipe
Componentes
Nota da Equipe de Tradução
A versão original deste texto foi completamente reescrita. Você está lendo uma versão antiga. Necessitamos de ajuda para traduzir novamente esta página. Mais detalhes nesta issue
Entendendo Componentes
Os componentes são um dos recursos mais poderosos do Vue. Eles ajudam a estender os elementos HTML para encapsular código de forma reusável. Em um alto nível, componentes são elementos personalizados que o Vue compila e anexa à sua instância. Em alguns casos, eles podem aparecer como um HTML nativo estendido com o atributo especial is
.
Todos os componentes Vue também são instância Vue, e portanto aceitam o mesmo objeto de opções (exceto para algumas poucas opções específicas de nível raiz) e oferecem os mesmos gatilhos de ciclo de vida.
Usando Componentes
Registrando Globalmente
Nós aprendemos nas seções anteriores que podemos criar uma nova instância do Vue com:
new Vue({ |
Para registrar um componente global, você pode usar Vue.component(tagName, options)
. Por exemplo:
Vue.component('my-component', { |
Observe que o Vue não força as regras da W3C para nomes de tags personalizadas (tudo minúsculo, obrigatoriamente com hífen entre palavras) embora seguir essa convenção seja considerado uma boa prática.
Uma vez registrado, um componente pode ser usado em uma instância como um elemento personalizado <my-component></my-component>
. Tenha certeza que o elemento é registrado antes de ser instanciado na raiz do Vue. Aqui está um exemplo completo:
<div id="example"> |
// registro |
O resultado renderizado será:
<div id="example"> |
Registrando Localmente
Você não é obrigado a registrar todo componente globalmente. É possível disponibilizar um componente somente no escopo de outra instância/componente, registrando-o com a opção components
:
var Child = { |
De fato, a mesma regra de encapsulamento se aplica para outros recursos registráveis do Vue, como as diretivas e os filtros.
Cuidados com o Uso no DOM
Quando usar o próprio DOM como seu template (isto é, usar a opção el
para montar a instância Vue em um conteúdo HTML já existente), você estará sujeito a algumas restrições inerentes a como o HTML funciona, pois o Vue só pode recuperar o conteúdo do template depois que o navegador o analisou e o normalizou. De maneira mais perceptível, alguns elementos como <ul>
, <ol>
, <table>
e <select>
têm restrições de quais elementos podem aparecer dentro deles, e alguns elementos como <option>
podem aparecer somente dentro de certos outros elementos.
Isso levará a problemas quando usar componentes personalizados no lugar de elementos que possuem tais restrições, por exemplo:
<table> |
O componente personalizado <my-row>
será jogado para fora da tabela como um conteúdo inválido, causando erros na renderização. Uma solução seria usar o atributo especial is
:
<table> |
Note que essas limitações não se aplicam se estiver usando templates baseados em Strings, de uma das seguintes maneiras::
<script type="text/x-template">
- Templates Strings do próprio JavaScript
- Componentes
.vue
Portanto, para casos simples, prefira usar Template Strings sempre que for possível.
Opção data
Deve Ser uma Função
A maioria das opções que podem ser informadas no construtor de uma instância Vue também podem ser usadas em um componente, com um caso em especial: a opção data
deve ser uma função. De fato, se você tentar isso:
Vue.component('my-component', { |
Você será interrompido com avisos no console, informando que data
deve ser uma função para instâncias de componentes. É bom entender por que as regras existem: vamos trapacear!
<div id="example-2"> |
var data = { counter: 0 } |
Uma vez que todas as três instâncias do componente compartilham o mesmo objeto data
, incrementar o contador no objeto reflete em todos eles! Ah não… Vamos corrigir isso, retornando um novo objeto de dados para cada instância do componente:
data: function () { |
Agora cada um dos nossos contadores tem seu próprio estado interno:
Compondo Componentes
Componentes existem para serem usados em conjunto, comumente em relacionamentos pai-filho: o componente A deve usar o componente B no seu próprio template. Eles inevitavelmente precisam se comunicar: o pai pode precisar passar dados para baixo ao seu próprio filho, e o filho pode precisar informar a seu pai sobre alguma coisa que aconteceu nele. Entretanto, também é muito importante manter o pai e o filho o mais desacoplados possível por meio de uma comunicação clara e definida. Isso garante que o código de cada componente possa ser escrito e entendido de forma relativamente isolada, os tornando mais fáceis de manter e potencialmente mais fáceis de reutilizar.
No Vue, o relacionamento pai-filho pode ser resumido como propriedades para baixo, eventos para cima. O pai passa dados para baixo por meio de propriedades, e o filho envia mensagens para o pai por meio de eventos. Vamos ver como eles funcionam a seguir.
Propriedades
Passando Dados com Propriedades
Toda instância de componente tem seu próprio escopo isolado. Isso significa que você não pode (e não deveria) referenciar diretamente dados do pai no template de um componente filho. Dados podem ser passados para componentes filhos usando propriedades.
Uma propriedade é um atributo personalizado para passar informação a partir do pai. Um filho deve declarar explicitamente o que ele espera receber usando a opção props
:
Vue.component('child', { |
Então nós podemos passar uma string simples para ela como:
<child message="Olá!"></child> |
Resultado:
camelCase vs. kebab-case
Atributos HTML são case-insensitive. Quando usar templates não baseados em Strings, nomes de propriedades camelCased precisam do equivalente em kebab-case (delimitado por hífen):
Vue.component('child', { |
<!-- kebab-case em HTML --> |
De novo, se você estiver usando string templates, essa limitação não se aplica.
Propriedades Dinâmicas
Semelhante à ligação de um atributo normal a uma expressão, nós podemos também usar o v-bind
para dinamicamente ligar propriedades a dados no pai. Sempre que os dados forem atualizados no pai, isso fluirá também para o filho:
<div> |
Você também pode usar a sintaxe abreviada para o v-bind
:
<child :my-message="parentMsg"></child> |
Resultado:
Se você quiser passar todas as propriedades em um objeto como props
, pode usar v-bind
sem informar um argumento (v-bind
em vez de v-bind:prop-name
). Por exemplo, dado o objeto todo
a seguir:
todo: { |
Então:
<todo-item v-bind="todo"></todo-item> |
Será equivalente a:
<todo-item |
Literal vs. Dinâmico
Um erro comum que iniciantes costumam fazer é tentar passar um valor numérico usando a sintaxe literal:
<!-- isto passa a String "1" --> |
No entanto, como isso é uma propriedade literal, o valor é passado como uma String "1"
ao invés de um número. Se quisermos passar um número JavaScript real, nós precisamos usar o v-bind
para que o seu valor seja avaliado como uma expressão JavaScript:
<!-- isto passa um número de verdade --> |
Fluxo de Dados Unidirecional
Todas as propriedades formam uma ligação unidirecional entre a propriedade do filho e o dado do pai: quando o pai é atualizado, o valor irá fluir para o filho, mas não o caminho inverso. Isso previne os componentes filhos de acidentalmente alterarem o estado dos pais, o que pode dificultar o entendimento dos dados de sua aplicação.
Além disso, sempre que o componente pai é atualizado, as propriedades do componente filho estarão atualizadas com o valor mais recente. Você não deveria tentar alterar uma propriedade dentro do componente filho. Se fizer isso, o Vue irá te avisar no console.
Geralmente há dois casos em que é tentador alterar uma propriedade:
A propriedade é usada para passar um valor inicial; o componente filho simplesmente quer usá-la como um dado local posteriormente.
A propriedade é passada como um valor bruto que precisa ser transformado.
A resposta apropriada para esses casos de uso são:
Defina um dado local que usa o valor da propriedade como o seu valor inicial:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}Defina um dado computado que é calculado a partir do valor da propriedade:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
Observe que objetos e Arrays em JavaScript são passados como referência, ou seja, se uma propriedade é um Array ou um objeto, alterá-la dentro do próprio filho irá afetar inadvertidamente o estado do pai.
Validação de Propriedades
É possível para um componente especificar requisitos para as propriedades que ele está recebendo. Se um requisito não é atendido, Vue emitirá avisos. É especialmente útil quando se está criando um componente com a intenção de que seja usado por outros desenvolvedores.
Em vez de definir as propriedades como um Array de Strings, você pode usar um objeto com os requisitos de validação:
Vue.component('example', { |
O type
pode ser um dos seguintes construtores nativos:
- String
- Number
- Boolean
- Function
- Object
- Array
- Symbol
Além disso, type
também pode ser uma função de construtor personalizada e a asserção será feita com uma verificação instanceof
.
Quando a validação de propriedade falha, Vue produz um aviso no console (se estiver utilizando uma compilação de desenvolvimento). Note que propriedades são validadas antes da instância do componente ser criada, portanto em funções default
ou validator
, propriedades da instância como data
, computed
ou methods
não estarão disponíveis.
Atributo Não-Prop
Um atributo não-prop é um atributo passado a um componente, mas que não tem uma propriedade correspondente definida através de props
.
Enquanto explicitamente definir props
é a forma recomendada de passar informações a componentes filhos, autores de bibliotecas de componentes não podem sempre prever o contexto no qual seus componentes poderão ser utilizados. Por isso componentes podem aceitar atributos arbitrários, os quais são adicionados ao elemento raiz do componente.
Por exemplo, imagine que estamos usando um componente bs-date-input
de terceiros, com um plugin Bootstrap que exige um atributo data-3d-date-picker
no input
. Nós podemos adicionar este atributo à nossa instância do componente:
<bs-date-input data-3d-date-picker="true"></bs-date-input> |
E o atributo data-3d-date-picker="true"
será automaticamente adicionado ao elemento raiz do bs-date-input
.
Substituindo/Mesclando Atributos
Imagine que este é o template do bs-date-input
:
<input type="date" class="form-control"> |
Para especificar um tema para nosso plugin de seleção de datas, precisaríamos adicionar uma classe específica, como essa:
<bs-date-input |
Neste caso, dois valores diferentes para class
estão definidos:
form-control
, configurado pelo próprio componente em seu templatedate-picker-theme-dark
, passado ao componente através de seu parent
Para mais atributos, o valor provido ao componente irá substituir o valor previamente definido no componente. Por exemplo, passar type="large"
irá sobrescrever type="date"
e provavelmente quebrar a funcionalidade! Por sorte, os atributos class
e style
são um pouco mais inteligentes e seus valores são mesclados automaticamente, tornando o valor final: form-control date-picker-theme-dark
.
Eventos Personalizados
Nós aprendemos que o pai pode passar dados para o filho usando propriedades, mas como nós comunicamos de volta para o pai quando alguma coisa acontece? É aí que o sistema de eventos personalizados do Vue entra.
Usando v-on
com Eventos Personalizados
Toda instância Vue implementa uma interface de eventos, o que significa que ela pode:
- Escutar um evento usando
$on(eventName)
- Disparar um evento usando
$emit(eventName, optionalPayload)
Observe que o sistema de eventos do Vue é separado da EventTarget API do navegador. Embora eles funcionem de maneira semelhante, o $on
e o $emit
não são apelidos para o addEventListener
e o dispatchEvent
.
Além disso, um componente pai pode ouvir eventos emitidos do componente filho usando o v-on
diretamente no template onde o componente filho é usado.
Você não pode usar o $on
para ouvir eventos emitidos pelo filho. Você deve usar o v-on
diretamente no template pai, como no exemplo abaixo.
Aqui está um exemplo:
<div id="counter-event-example"> |
Vue.component('button-counter', { |
{{ total }}
Neste exemplo, é importante notar que o componente filho ainda é completamente desacoplado do que acontece fora dele. Tudo o que ele faz é reportar informações sobre sua própria atividade, no caso de um componente pai se importar.
Agora um exemplo utilizando uma carga de dados (payload):
<div id="message-event-example" class="demo"> |
Vue.component('button-message', { |
{{ msg }}
Neste segundo exemplo, é importante observar que o componente filho ainda é completamente desacoplado do que acontece fora de si.
Tudo o que ele faz é reportar informação sobre sua própria atividade, inclusive o payload ao emissor do evento, apenas para o caso de algum componente pai se interessar por isso.
Ligando Eventos Nativos a Componentes
Pode haver momentos em que você deseja escutar um evento nativo ocorrido no elemento raiz de um componente. Nesses casos, use o modificador .native
para o v-on
:
<my-component v-on:click.native="doTheThing"></my-component> |
O Modificador .sync
2.3.0+
Em alguns casos nós podemos precisar de uma “ligação bidirecional” para uma propriedade - na verdade, no Vue 1.x era exatamente o que o modificador .sync
fornecia. Quando um componente filho altera uma propriedade que possui .sync
, a mudança de valor refletirá no pai. Isto é conveniente, no entanto leva a problemas de manutenção a longo prazo porque quebra a suposição de fluxo de dados unidirecional: o código que altera propriedades do filho está implicitamente afetando o estado do pai.
Por isso removemos o modificador .sync
quando a versão 2.0 foi lançada. No entanto, descobrimos que, de fato, existem casos em que isso pode ser útil, especialmente quando publicando componentes reutilizáveis. O que precisamos mudar é fazer um código no filho que afeta o estado do pai de forma mais consistente e explícita.
Na versão 2.3.0+ re-introduzimos o modificador .sync
para propriedades, mas desta vez ele é só “açúcar sintático”, o qual automaticamente se expande para uma escuta v-on
adicional.
Por exemplo, o seguinte:
<comp :foo.sync="bar"></comp> |
É expandido para:
<comp :foo="bar" @update:foo="val => bar = val"></comp> |
Para o componente filho atualizar o valor de foo
, ele precisa explicitamente emitir um evento em vez de alterar a propriedade diretamente:
this.$emit('update:foo', newValue) |
O modificador .sync
também pode ser usado junto com v-bind
ao utilizar um objeto para definir múltiplas propriedades de uma vez:
<comp v-bind.sync="{ foo: 1, bar: 2 }"></comp> |
Isto tem o efeito de adicionar escutas de atualização v-on
tanto para foo
quanto para bar
.
Componentes Suportando v-model
Eventos personalizados também podem ser usados para criar inputs personalizados que funcionam com v-model
. Lembre-se:
<input v-model="something"> |
É “açúcar sintático” para:
<input |
Quando usado com um componente, isto é simplificado para:
<custom-input |
Então, para funcionar com o v-model
, ele deveria (pode ser configurado em 2.2.0+):
- aceitar uma propriedade
value
- emitir um evento
input
com um novo valor
Vamos vê-lo em ação com um input monetário simples:
<currency-input v-model="price"></currency-input> |
Vue.component('currency-input', { |
No entanto, a implementação acima é bem ingênua. Por exemplo, é permitido aos usuários entrarem com múltiplos pontos e até letras algumas vezes - eca! Então, para aqueles que querem ver um exemplo não trivial, aqui está um componente monetário mais robusto:
Personalizando o Suporte ao v-model
Novo em 2.2.0+
Por padrão, o v-model
em um componente usa value
como propriedade e input
como evento, mas alguns tipos de input como checkboxes e radio buttons podem necessitar usar a propriedade value
para um propósito diferente. A opção model
pode evitar tal conflito:
Vue.component('my-checkbox', { |
<my-checkbox v-model="foo" value="algum valor"></my-checkbox> |
O acima será equivalente a:
<my-checkbox |
Observe que você ainda terá que declarar a propriedade checked
explicitamente.
Comunicação Não Pai-Filho
Algumas vezes, componentes podem precisar se comunicar sem serem pai/filho um do outro. Em casos simples, pode-se usar uma instância Vue vazia como barramento de eventos central:
var bus = new Vue() |
// no método do componente A |
// no hook created do componente B |
Para casos mais complexos, considere empregar um padrão de gerenciamento de estado.
Distribuição de Conteúdo com Slots
Ao usar componentes, muitas vezes é desejado compô-los assim:
<app> |
Há duas coisas para observar aqui:
O componente
<app>
não sabe qual conteúdo ele irá receber. Isso é decidido pelo componente pai que estiver usando<app>
.O componente
<app>
provavelmente possui seu próprio template.
Para que a composição funcione, precisamos de um jeito de entrelaçar o “conteúdo” do pai e o template do próprio componente. Este é um processo chamado de distribuição de conteúdo (ou “transclusão” se você estiver familiarizado com Angular). Vue.js implementa uma API de distribuição de conteúdo que é modelada a partir do atual rascunho de especificação de Web Components, usando o elemento especial <slot>
para servir como ponto de distribuição para o conteúdo original.
Escopo de Compilação
Antes de nos aprofundarmos para dentro da API, vamos primeiro esclarecer em qual escopo os conteúdos são compilados. Imagine um template assim:
<child-component> |
A message
deveria ser ligada aos dados do pai ou aos dados do filho? A resposta é do pai. Uma regra simples para o escopo do componente é:
Tudo que estiver no template do pai é compilado no escopo do pai; tudo que estiver no template do filho é compilado no escopo do filho.
Um erro comum é tentar ligar uma diretiva a um dado do filho no template do pai:
<!-- NÃO funciona --> |
Assumindo que someChildProperty
é uma propriedade no componente filho, o exemplo acima não funcionaria. O template do pai não tem conhecimento do estado do filho.
Se você precisa ligar diretivas do escopo-filho a um nó de um componente raiz, você deveria fazer isso no próprio template do componente filho:
Vue.component('child-component', { |
Da mesma forma, conteúdo distribuído será compilado no escopo dos pais.
Slot Simples
O conteúdo do pai será descartado a menos que o template do componente filho contenha pelo menos um elemento <slot>
. Quando há apenas um slot sem atributos, todo o fragmento de conteúdo será inserido em sua posição no DOM, substituindo o próprio slot.
Qualquer coisa originalmente dentro das tags <slot>
é considerado conteúdo reserva. O conteúdo reserva é compilado no escopo do filho e será exibido somente se o elemento hospedeiro estiver vazio e não tiver conteúdo a ser inserido.
Suponha que nós temos um componente chamado my-component
com o seguinte template:
<div> |
E um pai que usa o componente:
<div> |
O resultado renderizado será:
<div> |
Slots Nomeados
Elementos <slot>
têm um atributo especial name
, que pode ser usado para personalizar ainda mais o conteúdo a ser distribuído. Você pode ter múltiplos slots com nomes diferentes. Um slot nomeado combinará qualquer elemento que tenha um atributo <slot>
correspondente no fragmento de conteúdo.
Ainda pode haver um slot sem nome, que é o slot padrão que serve como saída para quando não há combinação de conteúdo. Se não houver nenhum slot padrão, o conteúdo não combinado será descartado.
Por exemplo, suponha que tenhamos um componente app-layout
com o seguinte template:
<div class="container"> |
Código do pai:
<app-layout> |
O resultado renderizado será:
<div class="container"> |
A API de distribuição de conteúdo é um mecanismo muito útil ao projetar componentes que devem ser compostos juntos.
Slot com Escopo
Novo em 2.1.0+
Um slot com escopo é um tipo especial de slot que funciona como um template reusável (em que podemos passar dados para ele) em vez de elementos já renderizados.
Em um componente filho, passe os dados para um slot como se você estivesse passando propriedades para um componente:
<div class="child"> |
No pai, um elemento <template>
com um atributo especial slot-scope
deve existir, indicando que ele é um template para um slot com escopo. O valor de slot-scope
será usado como o nome de uma variável temporária que guardará o objeto de propriedades passado pelo filho:
<div class="parent"> |
Se nós renderizarmos o código acima, a saída será:
<div class="parent"> |
No 2.5.0+,
slot-scope
não é mais limitado a<template>
e pode ser usado em qualquer elemento ou componente.
Um caso de uso mais típico para slots com escopo seria um componente de lista que permite que o consumidor do componente personalize como cada item deveria ser renderizado:
<my-awesome-list :items="items"> |
E o template para o componente de lista:
<ul> |
Desestruturação
O valor de slot-scope
é, de fato, uma expressão JavaScript válida que possa aparecer na posição de argumentos na assinatura de uma função. Isto significa que, em ambientes com suporte (em Componentes Single-File ou em navegadores modernos), você também pode utilizar a desestruturação do ES2015 na expressão:
<child> |
Componentes Dinâmicos
Você pode usar o mesmo ponto de montagem e alternar dinamicamente entre componentes usando o elemento <component>
e ligando dinamicamente seu atributo is
:
var vm = new Vue({ |
<component v-bind:is="currentView"> |
Se você preferir, você também pode ligar diretamente ao objeto do componente:
var Home = { |
keep-alive
Se você quiser manter componentes na memória para que você possa preservar seu estado ou evitar “re-renderização”, envolva um componente dinâmico em um elemento <keep-alive>
:
<keep-alive> |
Confira mais detalhes do <keep-alive>
na referência da API.
Outros Assuntos
Criando Componentes Reutilizáveis
Ao criar componentes, é bom pensar se você pretende reutilizá-lo em algum outro lugar mais tarde. É interessante que componentes únicos sejam fortemente acoplados, mas componentes reutilizáveis devem definir uma interface pública limpa e não fazer suposições sobre o contexto em que são usados.
A API para um componente Vue vem em três partes - propriedades, eventos e slots:
Propriedades permitem que o ambiente externo passe dados para o componente
Eventos permitem que o componente desencadeie efeitos colaterais no ambiente externo
Slots permitem que o ambiente externo componha o componente com conteúdo extra
Com as sintaxes abreviadas para v-bind
e v-on
, as intenções podem ser transmitidas de forma clara e sucinta no template:
<my-component |
Referências a Componentes Filhos
Apesar da existência de propriedades e eventos, algumas vezes você ainda pode precisar acessar diretamente um componente filho no JavaScript. Para conseguir isso, você tem que atribuir um identificador de referência para o componente filho, usando ref
. Por exemplo:
<div id="parent"> |
var parent = new Vue({ el: '#parent' }) |
Quando se utiliza ref
em conjunto com v-for
, a referência obtida será um Array contendo os componentes filhos que espelham a fonte de dados.
$refs
são populadas somente após o componente ser renderizado, e isso não é reativo. Servem apenas como válvula de escape para a manipulação direta - você deveria evitar o uso de $refs
nos templates ou nas propriedades computadas.
Componentes Assíncronos
Em grandes aplicações, podemos precisar dividir o aplicativo em pedaços menores e carregar o componente do servidor apenas quando for realmente necessário. Para facilitar, Vue permite que você defina seu componente como uma função de fábrica, desde que resolva de forma assíncra sua definição de componente. Vue só acionará a função de fábrica quando o componente realmente precisar ser renderizado e armazenará em cache o resultado para futuras “re-renderizações”. Por exemplo:
Vue.component('async-example', function (resolve, reject) { |
A função de fábrica recebe uma função callback resolve
, que deve ser chamada quando você recuperar a definição do componente do servidor. Você também pode chamar reject(reason)
para indicar que o carregamento falhou. O setTimeout
aqui é simplesmente para demonstração: como recuperar o componente fica totalmente por sua conta. Uma abordagem recomendada é usar juntamente com a ferramenta de divisão de código do Webpack:
Vue.component('async-webpack-example', function (resolve) { |
Você também pode retornar uma Promise
na função de fábrica. Então, com a sintaxe do Webpack 2 + ES2015 você pode fazer:
Vue.component( |
Ao usar registro local, também pode fornecer diretamente uma função que retorna Promise
:
new Vue({ |
Se você é usuário de Browserify e gostaria de usar componentes assíncronos, seu criador infelizmente deixou claro que carregamento assíncrono “não é algo que o Browserify irá algum dia suportar”. Oficialmente, pelo menos. A comunidade Browserify encontrou algumas soluções alternativas, que podem ser úteis para aplicações existentes e complexas. Para todos os outros cenários, nós recomendamos usar o Webpack, com um suporte assíncrono de primeira classe por padrão.
Componentes Assíncronos Avançados
Novo em 2.3.0+
A partir da versão 2.3.0+ a função de fábrica de componente assíncrono também pode retornar um objeto no seguinte formato:
const AsyncComp = () => ({ |
Observe que, quando usado como um componente de rota em vue-router
, essas propriedades serão ignoradas porque os componentes assíncronos são resolvidos antecipadamente, antes que a navegação da rota ocorra. Você também precisa usar vue-router
2.4.0+ se você deseja usar a sintaxe acima para componentes de rota.
Convenções para Nomeação de Componentes
Ao registrar componentes (assim como ao registrar propriedades), você pode usar kebab-case, camelCase, ou PascalCase.
// na definição de um componente |
Dentro de templates HTML, no entanto, você tem que usar os kebab-case equivalentes:
<!-- sempre use kebab-case em templates HTML --> |
Entretanto, ao usar templates baseados em Strings, nós não estamos ligados pelas restrições case-insensitive do HTML. Isso significa que mesmo no template você poderá referenciar seus componentes usando:
- kebab-case
- camelCase ou kebab-case se o componente foi definido usando camelCase
- kebab-case, camelCase ou PascalCase se o componente foi definido usando PascalCase
components: { |
<kebab-cased-component></kebab-cased-component> |
Isto significa que, pela sua flexibilidade, o PascalCase é a convenção de declaração universal e o kebab-case é a convenção de uso universal.
Se o componente não compõe conteúdo via slot
, você pode representá-lo como uma tag auto-contida usando uma /
depois do nome:
<my-component/> |
Novamente, isto funciona somente dentro de templates baseados em Strings, pois elementos personalizados auto-contidos não é um HTML válido e seu navegador não irá entendê-los.
Componentes Recursivos
Componentes podem recursivamente invocar a si mesmos em seus próprios templates. No entanto, eles só podem fazer isso se tiverem a opção name
definida:
name: 'unique-name-of-my-component' |
Quando você registra globalmente um componente usando Vue.component
, o identificador global é automaticamente atribuído como nome na opção name
.
Vue.component('unique-name-of-my-component', { |
Se você não tomar cuidado, componentes recursivos podem gerar loops infinitos:
name: 'stack-overflow', |
Um componente como acima resultará em um erro de “tamanho máximo da pilha excedido”, então tenha certeza que a sua invocação recursiva é condicional (isto é, usa um v-if
que eventualmente será false
).
Referências Circulares Entre Componentes
Vamos dizer que você está construindo uma árvore de arquivos de diretório, como um Finder ou um File Explorer. Você pode ter um componente tree-folder
com este template:
<p> |
Então um componente tree-folder-contents
com este template:
<ul> |
Ao olhar mais de perto, você verá que esses componentes serão na verdade tanto seus descendentes quanto seus antepassados na árvore de renderização - um paradoxo! Ao registrar globalmente um componente com Vue.component
, este paradoxo é resolvido para você automaticamente. Se é este o seu caso, pode parar de ler aqui.
Entretanto, se você está pegando/importando componentes usando um sistema de módulos, por exemplo, via Webpack ou Browserify, você terá um erro:
Failed to mount component: template or render function not defined. |
Para explicar o que está acontecendo, chamaremos nossos componentes de A e B. O sistema de módulos enxerga que precisa de A, mas primeiro A precisa de B, mas B precisa de A, mas A precisa de B, etc, etc. Ele fica preso em um loop, não sabendo como resolver completamente nenhum dos componentes sem primeiro resolver o outro. Para consertar isso, nós precisamos dar ao sistema de módulos um ponto em que ele possa dizer, “A precisa de B eventualmente, mas não há necessidade de resolver o B primeiro.”
No nosso caso, faremos esse ponto no componente tree-folder
. Nós sabemos que o filho que cria o paradoxo é o componente tree-folder-contents
, então esperaremos até que o gatilho de ciclo de vida beforeCreate
o registre:
beforeCreate: function () { |
Problema resolvido!
Templates Inline
Quando o atributo especial inline-template
está presente em um componente filho, o componente usará seu conteúdo interno como seu template, ao invés de tratá-lo como um conteúdo distribuído. Isto permite mais flexibilidade na criação de templates.
<my-component inline-template> |
Porém, os inline-template
dificultam o entendimento do escopo dos seus templates. Como uma melhor prática, prefira definir templates dentro do componente usando a opção template
ou em um elemento template
em um arquivo .vue
.
X-Templates
Outro jeito é definir templates dentro de um elemento script com o tipo text/x-template
, e então referenciar o template por um id
. Por exemplo:
<script type="text/x-template" id="hello-world-template"> |
Vue.component('hello-world', { |
Este cenário pode ser útil para demonstrações com templates muito grandes ou em aplicações extremamente pequenas, mas deve ser evitado por separar os templates do resto da definição do componente.
Componentes Estáticos Leves com v-once
Renderizar elementos HTML é muito fácil com Vue, mas algumas vezes você pode ter um componente que contém muito conteúdo estático. Nestes casos, é possível garantir que ele seja avaliado somente uma vez e então armazenado no cache, através da diretiva v-once
no elemento raiz, assim:
Vue.component('terms-of-service', { |