Vue.js para iniciantes lição 7: propriedades calculadas
→ Vue.js para iniciantes lição 8: componentes
O propósito da lição
O objetivo principal desta lição é criar nosso primeiro componente e explorar os mecanismos de transmissão de dados aos componentes.
Código inicial
Aqui está o código do arquivo
index.htmlencontrado na tag com a <body>qual começaremos:
<div id="app">
<div class="product">
<div class="product-image">
<img :src="image" />
</div>
<div class="product-info">
<h1>{{ title }}</h1>
<p v-if="inStock">In stock</p>
<p v-else>Out of Stock</p>
<p>Shipping: {{ shipping }}</p>
<ul>
<li v-for="detail in details">{{ detail }}</li>
</ul>
<div
class="color-box"
v-for="(variant, index) in variants"
:key="variant.variantId"
:style="{ backgroundColor: variant.variantColor }"
@mouseover="updateProduct(index)"
></div>
<button
v-on:click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"
>
Add to cart
</button>
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
</div>
</div>
</div>
Aqui está o código
main.js:
var app = new Vue({
el: '#app',
data: {
product: 'Socks',
brand: 'Vue Mastery',
selectedVariant: 0,
details: ['80% cotton', '20% polyester', 'Gender-neutral'],
variants: [
{
variantId: 2234,
variantColor: 'green',
variantImage: './assets/vmSocks-green.jpg',
variantQuantity: 10
},
{
variantId: 2235,
variantColor: 'blue',
variantImage: './assets/vmSocks-blue.jpg',
variantQuantity: 0
}
],
cart: 0,
},
methods: {
addToCart() {
this.cart += 1;
},
updateProduct(index) {
this.selectedVariant = index;
console.log(index);
}
},
computed: {
title() {
return this.brand + ' ' + this.product;
},
image() {
return this.variants[this.selectedVariant].variantImage;
},
inStock(){
return this.variants[this.selectedVariant].variantQuantity;
}
}
})
Tarefa
Não precisamos que todos os dados, métodos e propriedades calculadas no aplicativo Vue estejam localizados na instância raiz do Vue. Com o tempo, isso levará a um código que será muito difícil de manter. Em vez disso, gostaríamos de dividir o código em partes modulares que sejam mais fáceis de trabalhar e que tornem o desenvolvimento mais flexível.
A solução do problema
Vamos começar pegando o código existente e movendo-o para um novo componente.
É assim que o
main.jscomponente é registrado no arquivo :
Vue.component('product', {})
O primeiro argumento é o nome do componente de nossa escolha. O segundo é um objeto de opções semelhante ao que usamos para instanciar o Vue em tutoriais anteriores.
Na instância Vue, usamos uma propriedade
elpara organizar sua vinculação ao elemento DOM. No caso de um componente, é utilizada uma propriedade templateque define o código HTML do componente.
Vamos descrever o modelo de componente em um objeto com opções:
Vue.component('product', {
template: `
<div class="product">
… // HTML-, product
</div>
`
})
Existem várias maneiras de criar modelos no Vue. Agora estamos usando um literal de modelo, o conteúdo do qual está entre crases.
Se descobrir que o código do modelo não será colocado em um único elemento raiz, como um elemento
<div>com uma classe product, isso resultará na seguinte mensagem de erro:
Component template should contain exactly one root element
Em outras palavras, um template de componente só pode retornar um elemento.
Por exemplo, o seguinte modelo é bem formado porque é representado por apenas um elemento:
Vue.component('product', {
template: `<h1>I'm a single element!</h1>`
})
Mas se o modelo contiver vários irmãos, não funcionará. Aqui está um exemplo de um padrão ruim:
Vue.component('product', {
template: `
<h1>I'm a single element!</h1>
<h2>Not anymore</h2>
`
})
Como resultado, se um template incluir muitos elementos, por exemplo, um conjunto de elementos incluídos em nossa
<div>classe product, esses elementos deverão ser colocados em um elemento de contêiner externo. Como resultado, o modelo terá apenas um elemento raiz.
Agora que o modelo contém o código HTML que costumava estar no arquivo
index.html, podemos adicionar dados, métodos e propriedades computadas ao componente que estava anteriormente na instância raiz do Vue:
Vue.component('product', {
template: `
<div class="product">
…
</div>
`,
data() {
return {
//
}
},
methods: {
//
},
computed: {
//
}
})
Como você pode ver, a estrutura desse componente é quase completamente igual à estrutura da instância Vue com a qual trabalhamos anteriormente. Você notou que
dataagora isso não é uma propriedade, mas um método de um objeto com opções? Porque isto é assim?
A questão é que os componentes geralmente são criados com planos para reutilizá-los. Se tivermos muitos componentes
product, precisamos garantir que cada um deles tenha suas próprias instâncias de entidade data. Como dataagora é uma função que retorna um objeto com dados, cada componente receberá seu próprio conjunto de dados. Se a entidade datanão fosse uma função, então cada componenteproduct, onde quer que tais componentes fossem usados, conteria os mesmos dados. Isso vai contra a ideia de componentes reutilizáveis.
Agora que movemos o código relacionado ao produto para um componente nativo
product, o código para descrever a instância raiz do Vue se parece com este:
var app = new Vue({
el: '#app'
})
Agora só precisamos colocar o componente
productno código do arquivo index.html. Isso parecerá assim:
<div id="app">
<product></product>
</div>
Se você recarregar a página do aplicativo agora, ela retornará ao formato anterior.

Página do aplicativo
Se você agora olhar para as ferramentas de desenvolvedor do Vue, notará que há uma entidade raiz e um componente de produto.

Analisando o aplicativo com as ferramentas de desenvolvedor Vue
Agora, apenas para demonstrar a capacidade de reutilização dos componentes, vamos adicionar
index.htmlmais alguns componentesao códigoproduct. Na verdade, é assim que a reutilização de componentes é organizada. O códigoindex.htmlserá semelhante a este:
<div id="app">
<product></product>
<product></product>
<product></product>
</div>
E a página exibirá três cópias do cartão do produto.

Vários cartões de produtos exibidos em uma página
Observe que, no futuro, trabalharemos com um componente
product, então o códigoindex.htmlserá semelhante a este:
<div id="app">
<product></product>
</div>
Tarefa
Os aplicativos geralmente precisam de componentes para aceitar dados, parâmetros de entrada de entidades pai. Nesse caso, o pai do componente
producté a própria instância raiz do Vue.
Deixe a instância raiz do Vue ter uma descrição de alguns dados. Este dado indica se o usuário é titular de conta premium. O código para descrever uma instância Vue pode ser assim:
var app = new Vue({
el: '#app',
data: {
premium: true
}
})
Vamos decidir se os usuários premium têm direito a frete grátis.
Isso significa que queremos que o componente
productproduza premiumdiferentes informações de custo de envio , dependendo do que está escrito na propriedade raiz da instância Vue.
Como posso enviar os dados armazenados na propriedade da
premiuminstância raiz do Vue para o filho que é o componente product?
A solução do problema
No Vue, para transferir dados de entidades pai para filhos, uma propriedade de objeto com opções
propsdescritas pelos componentes é usada. Este é um objeto que descreve os parâmetros de entrada do componente, cujos valores devem ser definidos com base nos dados recebidos da entidade pai.
Vamos começar descrevendo que tipo de parâmetros de entrada o componente espera receber
product. Para fazer isso, adicione a propriedade correspondente ao objeto com as opções usadas ao criá-lo:
Vue.component('product', {
props: {
premium: {
type: Boolean,
required: true
}
},
// , ,
})
Observe que isso usa a capacidade integrada do Vue para validar os parâmetros passados para um componente. Ou seja, nós indicam que o tipo de parâmetro de entrada
premiumé Booleaneo que este parâmetro é necessário, definindo requireda true.
A seguir, vamos fazer uma alteração no modelo que exibe os parâmetros passados para o objeto. Ao exibir o valor da propriedade
premiumna página, teremos certeza de que o mecanismo que estamos investigando está funcionando corretamente.
<p>User is premium: {{ premium }}</p>
Até agora, está tudo bem. O componente
productsabe que receberá o parâmetro de tipo necessário para sua operação Boolean. Preparamos um local para exibir os dados relevantes.
Mas ainda não passamos o parâmetro para o
premiumcomponente. Você pode fazer isso usando um atributo personalizado que é semelhante à "linha" que leva a um componente através do qual é possível transmitir os parâmetros de entrada e, em particular premium.
Vamos modificar o código em
index.html:
<div id="app">
<product :premium="premium"></product>
</div>
Vamos atualizar a página.

Saída dos dados passados para o componente
Os parâmetros de entrada agora são passados para o componente. Vamos falar exatamente sobre o que acabamos de fazer.
Passamos ao componente um parâmetro de entrada, ou "atributo personalizado" chamado
premium. Ligamos esse atributo personalizado usando a construção de dois pontos a uma propriedadepremiumarmazenada em nossos dados de instância do Vue.
Agora a instância raiz do Vue pode passar para o
premiumcomponente filhoproduct. Uma vez que o atributo está vinculado a uma propriedadepremiumdos dados da instância Vue, o valor atualpremiumsempre será passado para o componenteproduct.
A imagem acima, ou seja, a inscrição
User is premium: true, prova que tudo foi feito corretamente.
Agora verificamos que o mecanismo de transferência de dados que estamos estudando funciona conforme o esperado. Se você olhar as ferramentas de desenvolvedor do Vue, verá que o componente
Productagora tem um parâmetro de entrada premiumque armazena um valor true.

Parâmetro de entrada do componente
Agora que os dados sobre se o usuário tem uma conta premium entram no componente, vamos usar esses dados para exibir as informações de custo de envio na página. Não vamos esquecer que, se o parâmetro for
premiumdefinido com um valortrue, o usuário tem direito a frete grátis. Vamos criar uma nova propriedade computadashippinge usar o parâmetro nelapremium:
shipping() {
if (this.premium) {
return "Free";
} else {
return 2.99
}
}
Se
this.premiumarmazenado em um parâmetro true, a propriedade computada shippingretornará Free. Caso contrário, ele retornará 2.99.
Vamos remover o código de saída do valor do parâmetro do modelo do componente
premium. Agora o elemento <p>Shipping: {{ shipping }}</p>que estava presente no código com o qual começamos hoje poderá mostrar informações sobre o custo de envio.

Os usuários premium recebem entrega gratuita de
texto que
Shipping: Freeaparece na página devido ao fato de que o componente é transmitido como um parâmetro de entradapremiumdefinido como um valortrue.
Maravilhoso! Agora, aprendemos como transferir dados de entidades pai para filhos e podemos usar esses dados no componente para gerenciar o custo de envio de mercadorias.
A propósito, é importante notar que você não deve alterar seus parâmetros de entrada em componentes filhos.
Oficina
Crie um novo componente
product-detailsque deve usar um parâmetro de entrada detailse ser responsável por renderizar a parte do cartão do produto que foi formado anteriormente usando o seguinte código:
<ul>
<li v-for="detail in details">{{ detail }}</li>
</ul>
Aqui está um modelo que você pode usar para resolver esse problema.
Aqui está a solução para o problema.
Resultado
Hoje foi sua primeira introdução aos componentes do Vue. Aqui está o que você aprendeu:
- Os componentes são blocos de código apresentados como elementos personalizados.
- Os componentes tornam seu aplicativo mais fácil de gerenciar, dividindo-o em partes reutilizáveis. Eles contêm descrições do componente visual e da funcionalidade da parte correspondente do aplicativo.
- Os dados do componente são representados por um método de um
data()objeto com opções. - Os parâmetros de entrada (
props) são usados para passar dados de entidades pai para entidades filho . - Podemos descrever os requisitos para os parâmetros de entrada que o componente assume.
- .
- .
- Vue .
Você está usando as ferramentas de desenvolvedor do Vue?
→ Vue.js para iniciantes lição 1: instância Vue
→ Vue.js para iniciantes, lição 2: atributos de vinculação
→ Vue.js para iniciantes lição 3: renderização condicional
→ Vue.js para iniciantes lição 4: exibição de listas
→ Vue .js para iniciantes lição 5: processamento de eventos
→ Vue.js para iniciantes lição 6: classes e estilos de ligação
→ Vue.js para iniciantes lição 7: propriedades calculadas
→ Vue.js para iniciantes lição 8: componentes
