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
- Básico sobre Componentes
Componentes em Detalhes
- Registro de Componentes
- Propriedades
- Eventos Personalizados
- Slots
- Dinâmicos & Assíncronos
- Lidando com Casos Extremos
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
- Componentes Single-File
- Testes Unitários
- Testing
- Suporte ao TypeScript
- Publicando em Produção
Escalonando
- Roteamento
- Gerenciamento de Estado
- Renderizando no Lado do Servidor
- Segurança
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
Você está navegando a documentação da v2.x e anterior. Para a v3.x, clique aqui.
Migração do Vue 1.x
FAQ
Wow - essa página é super longa! Isso significa que a versão 2.0 é completamente diferente, eu terei que aprender o básico de novo e a migração será praticamente impossivel?
Fico feliz que você tenha perguntado! A resposta é não. Cerca de 90% da API é a mesma e os conceitos básicos não mudaram. É longo porque queremos oferecer explicações muito detalhadas e incluir muitos exemplos. Tenha certeza, isso não é algo que você precisa ler de cima para baixo!
Por onde devo começar em uma migração?
Comece executando o assistente de migração em um projeto atual. Nós cuidadosamente minificamos e comprimimos um desenvolvedor sênior do Vue em uma interface de linha de comando simples. Sempre que eles reconhecem um recurso obsoleto, eles irão te informar, oferecer sugestões e fornecer links para mais informações.
Depois disso, navegue pela tabela de conteúdos desta página na barra lateral. Se você ver um tópico pelo o qual pode ser afetado, mas o assistente de migração não pegou, confira.
Se você tiver testes, execute-os e veja o que ainda falha. Se não tiver, basta abrir o app em seu navegador e ficar atento para avisos ou erros ao navegar.
Por enquanto, seu app deve ter migrado totalmente. Se você ainda deseja mais, pode ler o resto desta página - ou mergulhar no novo e melhorado guia de início. Muitas partes serão elimináveis, já que você já está familiarizado com os conceitos básicos.
Quanto demorará para migrar um app Vue da versão 1.x para a 2.0?
Depende de alguns fatores:
O tamanho do seu app (app pequeno ou médio provavelmente será inferior a um dia)
Quantas vezes você se distrai e começa a brincar com um recurso novo e legal. 😉 Não julgando, também aconteceu conosco enquanto construíamos a versão 2.0!
Quais recursos obsoletos você está usando. A maioria pode ser atualizada com encontrar-e-substituir, mas outros podem demorar alguns minutos. Se você não estiver seguindo as práticas recomendadas, o Vue 2.0 também tentará forçar você a fazê-lo. Isso é bom no longo prazo, mas também pode significar um refatoramento significativo (embora possivelmente em atraso).
Se eu atualizar para o Vue 2, também terei que atualizar o Vuex e o Vue Router?
Somente o Vue Router 2 é compatível com o Vue 2, então sim, você também terá que seguir o caminho de migração do Vue Router. Felizmente, a maioria dos apps não tem muito código de roteador, então provavelmente não demorará mais de uma hora.
Quanto ao Vuex, até a versão 0.8 é compatível com o Vue 2, portanto, você não está obrigado a atualizar. A única razão pela qual você pode querer atualizar imediatamente é aproveitar os novos recursos do Vuex 2, como módulos e boilerplate reduzido.
Templates
Instâncias de Fragmento removido
Cada componente deve ter exatamente um elemento raiz. As instâncias de fragmento não são mais permitidas. Se você tem um template como este:
<p>foo</p>
<p>bar</p>
Recomenda-se envolver todo o conteúdo em um novo elemento, como este:
<div>
<p>foo</p>
<p>bar</p>
</div>
Caminho de atualização
Execute seu conjunto de testes de ponta a ponta ou app após a atualização e procure avisos no console sobre vários elementos raiz em um template.
Gatilhos do Ciclo de Vida
beforeCompile
removido
Use o gatilho created
no lugar.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar todos os exemplos desse gatilho.
compiled
substituído
Use o novo gatilho mounted
no lugar.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar todos os exemplos desse gatilho.
attached
removido
Use uma verificação personalizada no DOM em outros gatilhos. Por exemplo, para substituir:
attached: function () {
doSomething()
}
Você pode usar:
mounted: function () {
this.$nextTick(function () {
doSomething()
})
}
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar todos os exemplos desse gatilho.
detached
removido
Use uma verificação personalizada no DOM em outros gatilhos. Por exemplo, para substituir:
detached: function () {
doSomething()
}
Você pode usar:
destroyed: function () {
this.$nextTick(function () {
doSomething()
})
}
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar todos os exemplos desse gatilho.
init
renomeado
Use o novo gatilho beforeCreate
em vez disso, que é essencialmente o mesmo. Foi renomeado para consistência com outros métodos do ciclo de vida.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar todos os exemplos desse gatilho.
ready
substituído
Use o novo gatilho mounted
em vez disso. Deve notar-se que, com mounted
, não há garantia de estar no documento pronto. Para isso, também inclua Vue.nextTick
/vm.$nextTick
. Por exemplo:
mounted: function () {
this.$nextTick(function () {
// código que assume que o this.$el está no documento
})
}
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar todos os exemplos desse gatilho.
v-for
Ordem dos Argumentos para Arrays no v-for
mudado
Ao incluir um índice
, a ordem dos argumentos para arrays costumava ser (índice, valor)
. Agora é (valor, índice)
para ser mais consistente com os métodos de array nativos do JavaScript, como por exemplo, forEach
e map
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de ordem de argumentos obsoleta. Observe que, se você nomear seus argumentos de índice algo incomum como position
ou num
, o assistente não irá sinalizá-los.
Ordem dos Argumentos para Objects no v-for
mudado
Ao incluir um nome/chave de propriedade, a ordem dos argumentos para objetos costumava ser (nome, valor)
. Agora é (valor, nome)
para ser mais consistente com os iteradores de objetos comuns, como o lodash
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de ordem de argumentos obsoleta. Observe que, se você nomear seus argumentos de chave como name
ou property
, o assistente não os sinalizará.
$index
e $key
removidos
As variáveis $index
e $key
implicitamente atribuídas foram removidas em favor de definí-las explicitamente no v-for
. Isso torna o código mais fácil de ler para desenvolvedores menos experientes com Vue e também resulta em um comportamento muito mais claro ao lidar com loops aninhados.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos dessas variáveis removidas. Se você perder alguma, também poderá ver erros no console, como: Uncaught ReferenceError: $index is not defined
track-by
substituído
track-by
foi substituído por uma key
, que funciona como qualquer outro atributo: sem o v-bind:
ou o prefixo :
, é tratado como uma string literal. Na maioria dos casos, você desejará usar uma vinculação dinâmica que espera uma expressão completa ao invés de uma chave. Por exemplo, no lugar de:
<div v-for="item in items" track-by="id">
Agora você irá escrever:
<div v-for="item in items" v-bind:key="item.id">
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de track-by
.
Intervalo de Valores do v-for
modificado
Antes, v-for="numero in 10"
teria o numero
começando em 0 e terminando em 9. Agora começa no 1 e termina no 10.
Caminho de atualização
Procure na sua base de código pelo regex /\w+ in \d+/
. Onde quer que apareça em um v-for
, verifique se você pode ser afetado.
Props
Opção coerce
de Props removido
Se você quiser coagir uma prop, configure um valor computado local com base nisso. Por exemplo, em vez de:
props: {
username: {
type: String
coerce: function (value) {
return value
.toLowerCase()
.replace(/\s+/, '-')
}
}
}
Você pode escrever:
props: {
username: String
},
computed: {
normalizedUsername: function () {
return this.username
.toLowerCase()
.replace(/\s+/, '-')
}
}
Existem algumas vantagens:
- Você ainda tem acesso ao valor original do prop.
- Você é forçado a ser mais explícito, dando ao valor coagido um nome que o diferencia do valor passado na prop.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos da opção coerce
.
Opção twoWay
de Props removido
Props agora estão sempre em sentido único. Para produzir efeitos colaterais no escopo dos pais, um componente precisa emitir um evento explicitamente em vez de depender da vinculação implícita. Para mais informações, veja:
- Eventos de componentes customizados
- Componentes de inputs customizados (usando eventos de componente)
- Gerenciamento de estado global
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos da opção twoWay
.
Modificadores .once
e .sync
no v-bind
removido
Props agora estão sempre em sentido único. Para produzir efeitos colaterais no escopo dos pais, um componente precisa emitir um evento explicitamente em vez de depender da vinculação implícita. Para mais informações, veja:
- Eventos de componentes customizados
- Componentes de inputs customizados (usando eventos de componente)
- Gerenciamento de estado global
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos dos modificadores .once
e .sync
.
Mutação de Prop descontinuado
Mutar um prop local agora é considerado anti-padrão, por exemplo, declarando um suporte e em seguida, definindo this.myProp = 'someOtherValue'
no componente. Devido ao novo mecanismo de renderização, sempre que o componente pai voltar a renderizar, as alterações locais do componente filho serão substituídas.
A maioria dos casos de mutar um prop pode ser substituído por uma dessas opções:
- uma propriedade
data
, com o prop usado para definir seu valor padrão - uma propriedade computada
Caminho de atualização
Execute seu teste de ponta a ponta ou app depois da atualização e procure por avisos no console sobre mutação de props.
Props em uma Instância Raiz substituído
Nas instâncias raiz do Vue (criadas com new Vue ({ ... })
), você deve usar propsData
ao invés de props
.
Caminho de atualização
Execute seu teste de ponta a ponta, se você tem um. Os testes com falha devem alertar o fato de que props passadas para instâncias raiz não funcionam mais.
Propriedades Computadas
cache: false
descontinuado
A invalidação de cache das propriedades computadas será removida nas futuras versões principais do Vue. Substitua quaisquer propriedade computada não cacheada por métodos, que terá o mesmo resultado.
Por exemplo:
template: '<p>mensagem: {{ timeMessage }}</p>',
computed: {
timeMessage: {
cache: false,
get: function () {
return Date.now() + this.message
}
}
}
Ou com métodos de componente:
template: '<p>mensagem: {{ getTimeMessage() }}</p>',
methods: {
getTimeMessage: function () {
return Date.now() + this.message
}
}
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos da opção cache: false
.
Diretivas Nativas do Vue
Verdadeiro/Falso com v-bind
modificado
Quando usado com v-bind
, os únicos valores falsos são agora: null
, undefined
e false
. Isso significa que 0
e arrays vazios renderizarão como verdadeiro. Então, por exemplo, v-bind: draggable = "''"
renderizará como draggable = "true"
.
Para atributos enumerados, além dos valores falsos acima, a string "false"
também será renderizada como attr = "false"
.
Observe que para outras diretivas (v-if
e v-show
por exemplo), o verdadeiro do Javascript normal ainda se aplica.
Caminho de atualização
Execute seus testes de ponta a ponta, se você tiver. Os testes com falha devem te alertar para qualquer parte do seu app que possa ser afetada por essa alteração.
Escutando Eventos Nativos nos Componentes com v-on
modificado
Quando usando em um componente, v-on
agora só escuta eventos customizados $emit
idos por aquele componente. Para escutar um evento nativo do DOM no elemento raiz, você pode usar o modificador .native
. Por exemplo:
<my-component v-on:click.native="doSomething"></my-component>
Caminho de atualização
Execute seu teste de ponta a ponta, se você tiver um. Os testes com falha devem te alertar para qualquer parte do seu app que possa ser afetada por essa alteração.
Atributo debounce
de Parâmetro para v-model
removido
Debounce é usado para limitar a frequência com que executamos os pedidos Ajax e outras operações custosas. O atributo debounce
do Vue para v-model
tornou isso fácil para casos muito simples, mas na verdade atrasa as atualizações de estado em vez das operações custosas. É uma diferença sutil, mas vem com limitações à medida que uma aplicação cresce.
Essas limitações tornam-se aparentes ao projetar um indicador de pesquisa, como este por exemplo:
Usando o atributo debounce
, não haveria nenhuma maneira de detectar o estado “Digitação”, pois perdemos acesso ao estado em tempo real do input. Ao desacoplar a função de atraso do Vue no entanto, podemos atrasar apenas a operação que queremos limitar, eliminando os limites nos recursos que podemos desenvolver.
<!--
Usando a função `debounce` do lodash ou outra
biblioteca de utilidades dedicada, sabemos que a
implementação de atraso específica que usamos
será a melhor da sua classe - e podemos usá-la em QUALQUER lugar.
Não somente no nosso template.
-->
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.js"></script>
<div id="debounce-search-demo">
<input v-model="searchQuery" placeholder="Digite algo">
<strong>{{ searchIndicator }}</strong>
</div>
new Vue({
el: '#debounce-search-demo',
data: {
searchQuery: '',
searchQueryIsDirty: false,
isCalculating: false
},
computed: {
searchIndicator: function () {
if (this.isCalculating) {
return '⟳ Buscando novos resultados'
} else if (this.searchQueryIsDirty) {
return '... Digitando'
} else {
return '✓ Pronto'
}
}
},
watch: {
searchQuery: function () {
this.searchQueryIsDirty = true
this.expensiveOperation()
}
},
methods: {
// É aqui que o debounce realmente deve ficar.
expensiveOperation: _.debounce(function () {
this.isCalculating = true
setTimeout(function () {
this.isCalculating = false
this.searchQueryIsDirty = false
}.bind(this), 1000)
}, 500)
}
})
Outra vantagem desta abordagem é que haverá momentos em que o debounce
não é a função wrapper correta. Por exemplo, ao usar uma API para sugestões de pesquisa, esperar para oferecer sugestões até que o usuário pare de digitar por um período de tempo não é uma experiência ideal. O que você provavelmente quer, em vez disso, é uma função de limitação. Agora, já que você está usando uma biblioteca de utilidades como lodash, a refatoração para usar a função throttle
, leva apenas alguns segundos.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do atributo debounce
.
Atributos lazy
ou number
de Paramêtros para v-model
substituído
Os atributos lazy
e number
agora são modificadores, para tornar mais claro o que isso significa, ao invés de:
<input v-model="name" lazy>
<input v-model="age" type="number" number>
Você usará:
<input v-model.lazy="name">
<input v-model.number="age" type="number">
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos destes atributos.
Atributo value
com v-model
removido
Agora o v-model
não se preocupa mais com o valor inicial do atributo value
. Em vez disso, tratará os dados da instância Vue como a fonte da verdade.
Isso significa que esse elemento:
<input v-model="text" value="foo">
apoiado por esses dados:
data: {
text: 'bar'
}
vai renderizar um valor de “bar” ao invés de “foo”. O mesmo vale para <textarea>
com conteúdo existente. Ao invés de:
<textarea v-model="text">
hello world
</textarea>
Você deve garantir que seu valor inicial para text
é “hello world”.
Caminho de atualização
Execute seu teste de ponta a ponta, após atualizar o app e busque por avisos no console sobre linhas de atributo value
com v-model
.
v-model
com v-for
Iterando Valores Primitivos removido
Casos como esse não funcionam mais:
<input v-for="str in strings" v-model="str">
A motivo é que este é o equivalente JavaScript para o qual o <input>
compilaria:
strings.map(function (str) {
return createElement('input', ...)
})
Como você pode ver, o vínculo bidirecional do v-model
não faz sentido aqui. Definir str
para outro valor na função de iteração não fará nada porque é apenas uma variável local no escopo da função.
Em vez disso, você deve usar um array de objects para que v-model
possa atualizar o campo no objeto. Por exemplo:
<input v-for="obj in objects" v-model="obj.str">
Caminho de atualização
Execute seu teste de ponta a ponta, se você tiver um. Os testes com falha devem te alertar para qualquer parte do seu app que possa ser afetada por essa alteração.
v-bind:style
com Sintaxe de Objeto e !important
removido
Isso não irá mais funcionar:
<p v-bind:style="{ color: myColor + ' !important' }">Olá</p>
Se você realmente precisa substituir outro !important
, você deve usar a sintaxe de string:
<p v-bind:style="'color: ' + myColor + ' !important'">Olá</p>
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vinculação de estilo com !important
em objetos.
v-el
e v-ref
subtituído
Para simplificar, v-el
e v-ref
foram incorporados no atributo ref
, acessível em uma instância de componente por meio de $refs
. Isso significa que v-el:my-element
se tornaria ref="myElement"
e v-ref:my-component
se tornaria ref="myComponent"
. Quando usado em um elemento normal, o ref
será o elemento DOM, e quando usado em um componente, a ref
será a instância do componente.
Como o v-ref
não é mais uma diretiva, mas um atributo especial, ele também pode ser definido dinamicamente. Isto é especialmente útil em combinação com v-for
. Por exemplo:
<p v-for="item in items" v-bind:ref="'item' + item.id"></p>
Anteriormente, v-el
/v-ref
combinado com v-for
produziria um array de elementos/componentes, pois não havia como dar a cada item um nome único. Você ainda pode obter este comportamento dando a cada item o mesmo ref
:
<p v-for="item in items" ref="items"></p>
Diferente das versões 1.x, esses $refs
não são reativos, porque eles são registrados/atualizados durante o próprio processo de renderização. Fazê-los reativos exigiria renderizações duplicadas para cada mudança.
Por outro lado, $refs
são projetados principalmente para acesso programático em JavaScript - não é recomendado confiar neles em templates, pois isso significaria referir-se ao estado que não pertence à instância em si. Isso violaria o modelo de visão orientado por dados do Vue.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de v-el
e v-ref
.
v-else
com v-show
removido
v-else
não funciona mais com v-show
. Use v-if
com uma expressão de negação ao invés disso. Por exemplo, ao invés de:
<p v-if="foo">Foo</p>
<p v-else v-show="bar">Não foo, mas bar</p>
Você pode usar:
<p v-if="foo">Foo</p>
<p v-if="!foo && bar">Não foo, mas bar</p>
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de v-else
e v-show
.
Diretivas Customizadas simplificado
As diretivas têm um escopo de responsabilidade muito reduzido: agora são usadas apenas para a aplicação de manipulações DOM diretas de baixo nível. Na maioria dos casos, você preferirá usar componentes como a principal abstração de reuso de código.
Algumas das diferenças mais notáveis incluem:
- As diretivas não têm mais instâncias. Isso significa que não há mais
this
dentro de diretivas gatilho. Em vez disso, eles recebem tudo o que podem precisar como argumentos. Se você realmente tem de persistir o estado através dos gatilhos, você pode fazer isso noel
. - Opções assim como
acceptStatement
,deep
,priority
, etc foram todas removidas. Para substituir as diretivastwoWay
, veja esse exemplo. - Alguns dos gatilhos atuais tem um comportamento diferente e também existem novos gatilhos.
Felizmente, desde que as novas diretivas estão mais simples, você pode dominá-las mais facilmente. Leia o novo Guia de customização de diretivas para aprender mais.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de diretivas definidas. O assistente sinalizará todos eles, é provável que na maioria dos casos você desejará refatorar para um componente.
Modificador de Diretiva .literal
removido
O modificador literal
foi removido pois o mesmo pode ser facilmente alcançado fornecendo uma string literal como valor.
Por exemplo, você pode atualizar:
<p v-my-directive.literal="foo bar baz"></p>
para:
<p v-my-directive="'foo bar baz'"></p>
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do modificador .literal
em diretivas.
Transições
Atributo transition
substituído
O sistema de transições do Vue mudou um pouco drasticamente e agora usamos <transition>
e <transition-group>
como elementos wrapper, ao invés do atributo transition
. É recomendado ler o novo Guia de transições para aprendar mais.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do atributo transition
.
Vue.transition
para Transições Reutilizáveis substituído
Com o novo sistema de transições, agora você pode usar componentes para transições reutilizáveis.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do Vue.transition
.
Atributo de Transição stagger
removido
Se precisa escalonar as transições da lista, você pode controlar o tempo ajustando e acessando um data-index
(ou atributo similar) em um elemento. Veja um exemplo aqui.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do atributo transition
. Durante sua atualização, você pode fazer a transição (trocadilho muito intencional) para a nova estratégia de escalonação também.
Eventos
Opção events
removido
Agora os manipuladores de eventos devem ser registrados no gatilho created
ao invés disso. Veja o guia de migração para $dispatch
e $broadcast
para exemplo detalhado.
Vue.directive('on').keyCodes
substituído
A nova e mais concisa maneira de configurar keyCodes
é através de Vue.config.keyCodes
. Por exemplo:
// ative v-on:keyup.f1
Vue.config.keyCodes.f1 = 112
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos da antiga sintaxe de configuração keyCode
.
$dispatch
e $broadcast
substituído
$dispatch
e $broadcast
foram removidos em favor de uma comunicação mais explícita entre componentes e soluções de gerenciamento de estado mais sustentáveis, como o Vuex.
O problema é que os fluxos de eventos que dependem da estrutura de árvore de um componente podem ser difíceis de serem entendidos e muito frágeis quando a árvore se torna grande. Eles não escalam bem e apenas o prepara para dor mais tarde. $dispatch
e $broadcast
também não resolvem a comunicação entre componentes irmãos.
Um dos usos mais comuns para esses métodos é se comunicar entre um pai e seus filhos diretos. Nesses casos, você pode escutar um $emit
de um filho com v-on
. Isso permite que você mantenha a conveniência dos eventos com uma explicitação adicional.
No entanto, quando se comunica entre descendentes distantes e ancestrais, $emit
não irá ajudá-lo. Em vez disso, a atualização mais simples possível seria usar um hub de eventos centralizado. Isso tem o benefício adicional de permitir que você se comunique entre componentes, independentemente de onde eles estão na árvore de componentes - mesmo entre irmãos! Como as instâncias do Vue implementam uma interface de emissor de eventos, você pode usar uma instância do Vue vazia para esse propósito.
Por exemplo, digamos que temos um app ToDo estruturado assim:
Todos
├─ NewTodoInput
└─ Todo
└─ DeleteTodoButton
Podemos gerenciar a comunicação entre componentes com este único hub de eventos:
// Este é o hub de eventos que usaremos em cada
// componente para se comunicar entre eles
var eventHub = new Vue()
Então, em nossos componentes podemos usar $emit
, $on
, $off
para emitir eventos, escutar eventos e limpar os escutadores de eventos, respectivamente:
// NewTodoInput
// ...
methods: {
addTodo: function () {
eventHub.$emit('add-todo', { text: this.newTodoText })
this.newTodoText = ''
}
}
// DeleteTodoButton
// ...
methods: {
deleteTodo: function (id) {
eventHub.$emit('delete-todo', id)
}
}
// Todos
// ...
created: function () {
eventHub.$on('add-todo', this.addTodo)
eventHub.$on('delete-todo', this.deleteTodo)
},
// É bom limpar os escutadores de evento
// antes de um componente ser destruído.
beforeDestroy: function () {
eventHub.$off('add-todo', this.addTodo)
eventHub.$off('delete-todo', this.deleteTodo)
},
methods: {
addTodo: function (newTodo) {
this.todos.push(newTodo)
},
deleteTodo: function (todoId) {
this.todos = this.todos.filter(function (todo) {
return todo.id !== todoId
})
}
}
Esse padrão pode servir como um substituto para $dispatch
e $broadcast
em cenários simples, mas para casos mais complexos, é recomendável usar uma camada de gerenciamento de estado dedicada, como o Vuex.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de $dispatch
e $broadcast
.
Filtros
Filtros Fora da Interpolação de Texto removido
Os filtros agora só podem ser usados dentro das interpolações de texto (tags {{ }}
). No passado, descobrimos que usar filtros dentro de diretivas, como v-model
, v-on
, etc levaram a mais complexidade do que o conveniente. Para a filtragem de lista no v-for
, também é melhor mover essa lógica para JavaScript como propriedades computadas, para que também possa ser reutilizado em todo o seu componente.
Em geral, sempre que algo puder ser alcançado em JavaScript simples, queremos evitar a introdução de uma sintaxe especial como filtros para cuidar da mesma preocupação. Veja como você pode substituir as diretivas internas de filtros do Vue:
Substituíndo o Filtro debounce
Ao invés de:
<input v-on:keyup="doStuff | debounce 500">
methods: {
doStuff: function () {
// ...
}
}
Use o debounce
do lodash (ou possivelmente o throttle
) para limitar diretamente a chamada do método custoso. Você pode alcançar o mesmo que acima, com isso:
<input v-on:keyup="doStuff">
methods: {
doStuff: _.debounce(function () {
// ...
}, 500)
}
Para obter mais informações sobre as vantagens desta estratégia, veja o exemplo com v-model
.
Substituíndo o Filtro limitBy
Ao invés de:
<p v-for="item in items | limitBy 10">{{ item }}</p>
Use o método do Javascript .slice
em uma propriedade computada:
<p v-for="item in filteredItems">{{ item }}</p>
computed: {
filteredItems: function () {
return this.items.slice(0, 10)
}
}
Substituíndo o Filtro filterBy
Ao invés de:
<p v-for="user in users | filterBy searchQuery in 'name'">{{ user.name }}</p>
Use o método do Javascript .filter
em uma propriedade computada:
<p v-for="user in filteredUsers">{{ user.name }}</p>
computed: {
filteredUsers: function () {
var self = this
return self.users.filter(function (user) {
return user.name.indexOf(self.searchQuery) !== -1
})
}
}
O método nativo filter
também pode gerenciar operações de filtragem muito mais complexas, porque você tem acesso ao poder total do JavaScript dentro das propriedades computadas. Por exemplo, se você quisesse encontrar todos os usuários ativos e buscar de forma insensível a maiúsculas e minúsculas ambos nome e email:
var self = this
self.users.filter(function (user) {
var searchRegex = new RegExp(self.searchQuery, 'i')
return user.isActive && (
searchRegex.test(user.name) ||
searchRegex.test(user.email)
)
})
Substituíndo o Filtro orderBy
Ao invés de:
<p v-for="user in users | orderBy 'name'">{{ user.name }}</p>
Use o orderBy
do lodash (ou possivelmente o sortBy
) em uma propriedade computada:
<p v-for="user in orderedUsers">{{ user.name }}</p>
computed: {
orderedUsers: function () {
return _.orderBy(this.users, 'name')
}
}
Você pode até ordenar por múltiplas colunas:
_.orderBy(this.users, ['name', 'last_login'], ['asc', 'desc'])
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de filtros sendo usados dentro de diretivas. Se você perder algum, também poderá ver erros no console.
Sintaxe de Argumentos para Filtros modificado
A sintaxe para argumentos agora se alinha melhor com a invocação de função Javascript. Então ao invés de usar argumentos delimitados por espaço:
<p>{{ date | formatDate 'YY-MM-DD' timeZone }}</p>
Nós cercamos os argumentos com parênteses e os delimitamos com vírgulas:
<p>{{ date | formatDate('YY-MM-DD', timeZone) }}</p>
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de filtros com a sintaxe antiga. Se você perder algum, também poderá ver erros no console.
Filtros de Texto Incorporados removido
Embora os filtros nas interpolações de texto ainda são permitidos, todos os filtros foram removidos. Em vez deles, é recomendável usar bibliotecas mais especializadas para resolver problemas em cada domínio (exemplos: date-fns
para formatar datas e accounting
para moedas.
Para cada um dos filtros de texto internos do Vue, mostraremos como você pode substituí-los abaixo. O código de exemplo poderá estar em funções auxiliares, métodos ou propriedades computadas.
Substituíndo o Filtro json
Você não precisa mais depurar, já que o Vue formatará bem a saída para você automaticamente, seja uma string, número, array ou objeto comum. Porém, se você quiser exatamente a mesma funcionalidade que o JSON.stringify
do JavaScript, você pode usá-lo em um método ou propriedade computada.
Substituíndo o Filtro capitalize
text[0].toUpperCase() + text.slice(1)
Substituíndo o Filtro uppercase
text.toUpperCase()
Substituíndo o Filtro lowercase
text.toLowerCase()
Substituíndo o Filtro pluralize
O pacote pluralize no NPM atende bem este propósito, mas se você quer apenas pluralizar uma palavra específica ou ter uma saída especial para casos como 0
, então também pode definir facilmente suas próprias funções de pluralize
. Por exemplo:
function pluralizeKnife (count) {
if (count === 0) {
return 'sem facas'
} else if (count === 1) {
return '1 faca'
} else {
return count + 'facas'
}
}
Substituíndo o Filtro currency
Para uma implementação muito ingênua, você poderia fazer algo como isto:
'R$' + price.toFixed(2)
Em muitos casos, porém, você ainda terá um comportamento estranho (exemplo: 0.035.toFixed(2)
arredonda para 0.04
, mas 0.045
arredonda para 0.04
). Para contornar esses problemas, você pode usar a biblioteca accounting
para formatar moedas de forma mais confiável.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de filtros de texto obsoletos. Se você perder algum, também poderá ver erros no console.
Filtros Bidirecionais substituído
Alguns usuários gostaram de usar filtros bidirecionais com v-model
para criar inputs interessantes com muito pouco código. Embora aparentemente simples no entanto, os filtros bidirecionais também podem ocultar uma grande complexidade - e até mesmo encorajar uma UX pobre ao atrasar as atualizações do estado. Em vez disso, os componentes que envolvem um input são recomendados como uma maneira mais explícita e rica em recursos para criar inputs personalizados.
Como exemplo, agora vamos percorrer a migração de um filtro de moeda bidirecional:
Na maior parte funciona bem, mas as atualizações de estado atrasadas podem causar um comportamento estranho. Por exemplo, tente digitar 9.999
em um desses inputs. Quando o input perde o foco, seu valor será atualizado para $10.00
. Ao olhar para o total calculado no entanto, você verá que 9.999
é o que está armazenado em nossos dados. A versão da realidade que o usuário vê está fora de sincronia!
Para iniciar a transição para uma solução mais robusta usando o Vue 2.0, primeiro envolva esse filtro em um novo componente <currency-input>
:
Isso nos permite adicionar um comportamento que um filtro por si só não poderia encapsular, como selecionar o conteúdo de um input no foco. Agora, o próximo passo será extrair a lógica de negócios do filtro. Abaixo, puxamos tudo para um objeto externo currencyValidator
:
Esse aumento da modularidade não só facilita a migração para a Vue 2, mas também permite que a análise e formatação da moeda sejam:
- testadas como unidades isoladas do seu código Vue
- usado por outras partes do seu app, como para validar a carga útil de uma ponta final de API
Tendo este validador extraído, nós também construíremos isso mais confortavelmente em uma solução mais robusta. As peculiaridades do estado foram eliminadas e, na verdade, é impossível para os usuários inserirem algo errado, semelhante ao que o input numérico nativo do navegador tenta fazer.
Ainda estamos limitados, porém, por filtros e pelo Vue 1.0 em geral, então vamos completar a atualização para o Vue 2.0:
Você pode notar que:
- Todos os aspectos do nosso input são mais explícitos, usando gatilhos do ciclo de vida e eventos DOM no lugar do comportamento oculto dos filtros bidirecionais.
- Agora podemos usar o
v-model
diretamente em nossos inputs personalizados, o que não é apenas mais consistente com as inputs normais, mas também significa que nosso componente é amigável ao Vuex. - Uma vez que não estamos mais usando opções de filtro que exigem um valor a ser retornado, nosso trabalho de moeda pode ser feito assincronamente. Isso significa que se tivéssemos muitos apps que precisassem trabalhar com moedas, poderíamos facilmente refatorar essa lógica em um microservice compartilhado.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de filtros usados em diretivas como v-model
. Se você perder algum, também poderá ver erros no console.
Slots
Slots Duplicados removido
Não é mais suportado ter vários <slot>
com o mesmo nome no mesmo template. Quando um slot é renderizado, ele é “usado” e não pode ser renderizado em outro lugar na mesma árvore de renderização. Se você precisa renderizar o mesmo conteúdo em vários lugares, passe-o como uma prop.
Caminho de atualização
Execute seu conjunto de testes de ponta a ponta ou app após a atualização e procure avisos no console sobre slots v-model
duplicados.
Estilizando o Atributo slot
removido
Conteúdo inserido através de <slot>
nomeado não preserva mais o atributo slot
. Use um elemento wrapper para estilizá-los, ou para casos de uso avançados, modifique o conteúdo inserido programaticamente usando funções de renderização.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar seletores CSS mirando slots nomeados (exemplo: [slot="my-slot-name"]
).
Atributos Especiais
Atributo keep-alive
substituído
keep-alive
não é mais um atributo especial, mas sim um componente wrapper, semelhante a <transition>
. Por exemplo:
<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>
Isso torna possível usar <keep-alive>
em múltiplos filhos condicionais:
<keep-alive>
<todo-list v-if="todos.length > 0"></todo-list>
<no-todos-gif v-else></no-todos-gif>
</keep-alive>
Quando <keep-alive>
tem vários filhos, eventualmente somente um será avaliado. Qualquer filho que não seja o primeiro será ignorado.
Quando usado em conjunto com <transition>
, certifique-se de aninhá-lo dentro:
<transition>
<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>
</transition>
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar atributos keep-alive
.
Interpolação
Interpolação dentro de Atributos removido
Interpolação com atributos não é mais válido. Por exemplo:
<button class="btn btn-{{ size }}"></button>
Deve ser atualizado para usar uma expressão inline:
<button v-bind:class="'btn btn-' + size"></button>
Ou uma propriedade/dado computado:
<button v-bind:class="buttonClasses"></button>
computed: {
buttonClasses: function () {
return 'btn btn-' + size
}
}
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de interpolação usada dentro de atributos.
Interpolação HTML removido
Interpolações HTML ({{{ foo }}}
) foram removidas em favor da diretiva v-html
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar interpolações HTML.
Vinculações de Vez Única substituído
Vinculações de vez única ({{* foo }}
) foram substituídas pela nova diretiva v-once
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar vinculações de vez única.
Reatividade
vm.$watch
modificado
Observadores criados via vm.$watch
agora são disparados antes que os componentes associados re-renderizem. Isso lhe dá a chance de atualizar o estado antes do componente re-renderizar, evitando atualizações desnecessárias. Por exemplo, você pode assistir um prop de componente e atualizar os próprios dados do componente quando o prop mudar.
Se você anteriormente confiava no vm.$watch
para fazer algo com o DOM após as atualizações de um componente, você pode fazê-lo no gatilho updated
do ciclo de vida.
Caminho de atualização
Execute seu conjunto de testes de ponta a ponta, se você tem um. Os testes com falha alertarão para o fato de que um observador está confiando no comportamento antigo.
vm.$set
modificado
vm.$set
agora é um apelido para Vue.set
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do uso obsoleto.
vm.$delete
modificado
vm.$delete
agora é um apelido para Vue.delete
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos do uso obsoleto.
Array.prototype.$set
removido
Use Vue.set
ao invés disso.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de .$set
em um array. Se você perder algum, poderá ver os erros no console sobre o método ausente.
Array.prototype.$remove
removido
Use Array.prototype.splice
ao invés disso. Por exemplo:
methods: {
removeTodo: function (todo) {
var index = this.todos.indexOf(todo)
this.todos.splice(index, 1)
}
}
Ou melhor ainda, passe aos métodos de remoção um index:
methods: {
removeTodo: function (index) {
this.todos.splice(index, 1)
}
}
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de .$remove
em um array. Se você perder algum, poderá ver erros no console sobre o método ausente.
Vue.set
e Vue.delete
em Instâncias Vue removido
Vue.set
e Vue.delete
não funcionam mais em instâncias Vue. Agora é obrigatório declarar corretamente todas as propriedades reativas de nível superior na opção data. Se você quiser excluir propriedades em uma instância do Vue ou seu $data
, defina-a como null.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.set
ou Vue.delete
em uma instância Vue. Se você perder algum, eles dispararão erros no console.
Substituíndo vm.$data
removido
Agora é proibido substituir uma instância raiz $data
de um componente. Isso evita alguns casos de borda no sistema de reatividade e torna o estado do componente mais previsível (especialmente com sistemas de verificação de tipos).
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de sobrescrita do vm.$data
. Se você perder algum, erros no console serão emitidos.
vm.$get
removido
Em vez disso, recupere dados reativos diretamente.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$get
. Se você perder algum, verá erros no console.
Métodos de Instância Focados no DOM
vm.$appendTo
removido
Use a API nativa do DOM:
myElement.appendChild(vm.$el)
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$appendTo
. Se você perder algum, verá erros no console.
vm.$before
removido
Use a API nativa do DOM:
myElement.parentNode.insertBefore(vm.$el, myElement)
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$before
. Se você perder algum, verá erros no console.
vm.$after
removido
Use a API nativa do DOM:
myElement.parentNode.insertBefore(vm.$el, myElement.nextSibling)
Ou se myElement
for o último filho:
myElement.parentNode.appendChild(vm.$el)
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$after
. Se você perder algum, verá erros no console.
vm.$remove
removido
Use a API nativa do DOM:
vm.$el.remove()
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$remove
. Se você perder algum, verá erros no console.
Métodos de Meta-Instância
vm.$eval
removido
Nenhum uso real. Se acontecer de você contar com esse recurso de alguma forma e não sabe como contornar a falta dele, publique no fórum para obter ideias.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$eval
. Se você perder algum, verá erros no console.
vm.$interpolate
removido
Nenhum uso real. Se acontecer de você contar com esse recurso de alguma forma e não sabe como contornar a falta dele, publique no fórum para obter ideias.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$interpolate
. Se você perder algum verá erros no console.
vm.$log
removido
Ao invés disso use o Vue Devtools para uma experiência de depuração otimizada.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de vm.$log
. Se você perder algum, verá erros no console.
Opções da Instância DOM
replace: false
removido
Agora os componentes substituem sempre o elemento ao qual estão vinculados. Para simular o comportamento de replace: false
, você pode envolver seu componente raiz com um elemento semelhante ao que você está substituíndo. Por exemplo:
new Vue({
el: '#app',
template: '<div id="app"> ... </div>'
})
Ou com uma função de renderização:
new Vue({
el: '#app',
render: function (h) {
h('div', {
attrs: {
id: 'app',
}
}, /* ... */)
}
})
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de replace: false
.
Configuração Global
Vue.config.debug
removido
Não é mais necessário, já que os avisos vêm com rastreamentos de pilha por padrão agora.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.config.debug
.
Vue.config.async
removido
Funcionamento assíncrono agora já é necessário para a performance de renderização.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.config.async
.
Vue.config.delimiters
substituído
Isso foi retrabalhado como uma opção no nível de componente. Isso permite que você use delimitadores alternativos dentro da sua aplicação sem quebrar componentes de terceiros.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.config.delimiters
.
Vue.config.unsafeDelimiters
removido
Interpolação do HTML já foi removida por causa do v-html
.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.config.unsafeDelimiters
. Depois disso, o assistente também encontrará instâncias de interpolação HTML para que você possa substituí-las por v-html
.
API Global
Vue.extend
com el
removido
A opção el
não pode mais ser usada no Vue.extend
. Só é válida como uma opção na criação de instância.
Caminho de atualização
Execute seu conjunto de testes de ponta a ponta ou app após a atualização e procure avisos no console sobre a opção el
no Vue.extend
.
Vue.elementDirective
removido
Use componentes ao invés disso.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.elementDirective
.
Vue.partial
removido
Parciais foram removidos em favor de fluxo de dados mais explícito entre componentes, usando props. A menos que você esteja usando um partial
em uma área crítica para desempenho, a recomendação é usar um componente normal em vez disso. Se você estiver vinculando dinamicamente o name
de um partial
, poderá usar um componente dinâmico.
Se você estiver usando partial
em uma parte crítica para o desempenho do seu aplicativo, então você deve atualizar para componentes funcionais. Eles devem estar em um arquivo JS/JSX simples (em vez de um arquivo .vue
) e são sem estados ou instâncias, como partial
. Isso torna a renderização extremamente rápida.
Um benefício de componentes funcionais sobre parciais é que eles podem ser muito mais dinâmicos, porque eles lhe permitem acessar todo o poder do JavaScript. No entanto, há um custo para este poder. Se você nunca usou um framework de componentes com funções de renderização antes, elas podem demorar um pouco mais para se aprender.
Caminho de atualização
Execute o assistente de migração em sua base de código para encontrar exemplos de Vue.partial
.