componentes
eventos
index.html
main.js
<!DOCTYPE html>
<html>
<head>
<title>Meme Generator</title>
</head>
<body>
<div id="app">
<h1>Meme Name</h1>
</div>
<script src="./assets/js/main.js"></script>
</body>
</html>
let meme = 'Dog Meme';
Nós precisamos de alguma forma mostrar o valor da variável meme dentro do <h1> no nosso html.
index.html
<script src="https://unpkg.com/vue"></script>
O primeiro passo é incluir o script do Vue no nosso projeto.
E assim usar a nossa primeira expressão JavaScript
index.html
main.js
E no nosso main.js, vamos incluir a instância do Vue
const app = new Vue({
el: '#app',
data: {
meme: 'Dog'
}
})
<div id="app">
<h1>{{ meme }}</h1>
</div>
Vamos ver o nome Dog dentro de nossa tag <h1>
A instância Vue é a raiz de nossa aplicação. Ela é criada passando um objeto com suas opções.
Nesse objeto tem uma variedade de propriedades opcionais que dão a instância a habilidade de armazenar dados e realizar ações.
const app = new Vue({options})
A instância Vue é então conectada com um elemento de sua escolha, formando um relacionamento entre a instância e uma parte do DOM (Document Object Model).
Em outras palavras, nós estamos ativando o Vue na div com o id app, colocando '#app', como o elemento (el) da nossa instância.
el: '#app'
Uma instância do Vue possui a propriedade data para inserir os dados
Os dados da instância podem ser acessados dentro do elemento em que a instância está plugada.
data: {
meme: 'Dog'
}
<div id="app">
<h1>{{ meme }}</h1>
</div>
Se nós queremos que algum dado seja mostrado no html, é preciso adicionar as chaves duplas entre o valor a ser exibido.
<h1>{{ meme }}</h1>
{{ title.toUpperCase() }}
{{ firstName + ' ' + lastName }}
{{ ok ? 'SIM' : 'NÃO' }}
Para provar isso, vamos abrir o console e alterar o valor de nossa string meme. Vamos ver o que acontece.
Busquem conhecimento!!
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeDestroy() {},
destroyed() {},
data: {
title: 'Meme Generator',
},
created() {
console.log('created');
},
Por exemplo, o gatilho created pode ser utilizado para executar código logo após a instância ser criada:
data: {
title: '',
},
created() {
// setar o title;
},
Queremos formatar nosso título, porém adicionar qualquer lógica mais complexa, pode fazer com que nosso HTML fique com uma manutenção mais complicada. Por exemplo:
<div id="app">
<h1>{{ title.replace(' ', '-') }}</h1>
</div>
Desde que dados computados calculam um valor no lugar de armazenar um valor, vamos adicionar a opção para dados computados em nossa instância:
Quando o newTitle é chamado, ele faz o replace da string retornando o novo valor. Se o title for atualizado, o dado computado vai atualizar, caso contrário seu valor vai ficar salvo em cache.
data: {...},
computed: {
newTitle() {
return this.title.replace(' ', '-');
},
},
<div id="app">
<h1>{{ newTitle }}</h1>
</div>
computed: {
fullName() {
return this.firstName + ' ' + this.lastName;
},
showUrl() {
return `${this.url}/${this.id}`;
}
}
<h1 v-if="showTitle">
{{ titleFormatted }}
</h1>
data: {
showTitle: true
}
data: {
showTitle: false
}
<div v-if="emptyTable()">
Nenhum resultado encontrado!
</div>
<div v-else>
<table></table>
</div>
<div v-if="isProfessor()">
<h1>Professor</h1>
</h1>
<div v-else-if="isVeterano()">
<p>Veterano</p>
</div>
<div v-else>
<p>Calouro</p>
</div>
<div v-show="isLoading">
<loader />
</div>
Vamos conectar o link de uma imagem
com o elemento <img> em seu atributo src, para mostrar alguma imagem de um meme específico.
Nesse tópico, vamos explorar maneiras de conectar dados aos atributos de elementos HTML.
index.html
Nós queremos que os dados da imagem, sejam dinamicamente conectados.
Dado do caminho da imagem.
main.js
<div id="app">
<h1 v-if="showTitle">
{{ titleFormatted }}
</h1>
<img src="">
</div>
const app = new Vue({
el: '#app',
data: {
title: '',
image: {
path: './assets/images/dog-meme.png'
},
}
})
Para víncular o valor do src da imagem no nosso objeto data com nossa tag img, nós vamos usar a diretiva v-bind do Vue.
v-bind
O que vai ser avaliado como:
<img :src="image.path">
<img src="./assets/images/dog-meme.png">
<img :src="image.path">
data: {
image: {
path: './assets/images/dog-meme.png'
},
}
index.html
main.js
Se o path da imagem for alterado o src vai atualizar, e a nova imagem vai aparecer.
Isso acontece devido ao src da imagem, estar vinculado com nosso objeto data. (Data Binding)
image: {
path: 'https://imgflip.com/s/meme/Scared-Cat.jpg'
}
<a :href="link">Link</a>
<div :class="divClass">Div</div>
<span :title="tooltip">Span</span>
<button :disabled="isDisabled">Button</button>
v-bind
:
:
#main-content {
word-wrap: break-word;
}
#main-image {
width: 100%;
height: auto;
max-height: 800px;
}
.text {
color: #fff;
font-size: 4.5vw;
line-height: 3.8vw;
padding: 15px;
position: absolute;
text-transform: uppercase;
text-shadow: 3px 3px 3px #000;
}
assets/css/style.css
Incluir meta tags e bootstrap 4
<head>
<!-- Meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap 4 CSS -->
<link rel="stylesheet" href="https://bootswatch.com/4/lux/bootstrap.min.css">
<!-- Style -->
<link rel="stylesheet" href="./assets/css/style.css">
<!-- Vue.js -->
<script src="https://unpkg.com/vue"></script>
<title>Meme Generator</title>
</head>
<body>
<div id="app" class="row m-0 py-2 text-center">
<div id="main-content" class="col-md-6 d-block mx-auto position relative">
<img id="main-image" :src="image.path" :title="image.title">
</div>
<div class="col-md-6">
<h1 v-if="showTitle" class="mt-2">
{{ titleFormatted }}
</h1>
<div class="form-group">
<input type="text" placeholder="Top text" class="form-control">
</div>
</div>
</div>
<script src="./assets/js/main.js"></script>
</body>
<p class="fixed-top text">Top text</p>
<img id="main-image" :src="image.path" :title="image.title">
Como fazer a conexão entre o que digitamos no input, e o texto acima da imagem?
Precisamos fazer uma interligação entre o input e o elemento <p> acima da nossa imagem usando a diretiva v-model do Vue.
Alterar a view atualiza o model
Alterar o model atualiza a view
Two-Way Data Binding
data: {
text: {
top: '',
}
},
main.js
<div class="form-group">
<input
type="text"
placeholder="Top text"
class="form-control"
v-model="text.top"
>
</div>
<p class="fixed-top text">
{{ text.top }}
</p>
index.html
index.html
<link href="https://fonts.googleapis.com/css?family=Passion+One&display=swap" rel="stylesheet">
index.html
.text {
...,
font-family: 'Passion One';
...
}
style.css
Nós precisamos de um botão reset para ouvir eventos de click, para então acionar um método que vai limpar o formulário.
Vamos adicionar o botão com a diretiva v-on do Vue que permite ouvir eventos do DOM, e invocar um método nosso que vai limpar o formulário.
Vamos adicionar o botão abaixo dos inputs
Nós estamos usando a diretiva v-on abreviada = @ para ouvir o evento de click e acionar o método resetInputs()
v-on
@
<button
class="btn btn-outline-primary"
@click="resetInputs()"
>
Reset
</button>
// elemento recebeu o foco
@focus="method"
// elemento perdeu o foco
@blur="method"
// botão de submit pressionado
@submit="method"
// qualquer tecla foi pressionada
@keydown="method"
// a tecla foi solta
@keyup="method"
A instância Vue tem uma propriedade opcional para seus métodos. Então nós vamos adicionar o método resetInputs que realiza a ação de limpar o formulário
methods: {
resetInputs() {
this.text.top = '';
this.text.bottom = '';
},
},
No lugar de escrever o método como
nós podemos escrever usando a abreviação do ES6 sendo:
São duas maneiras equivalentes de escrever uma função.
resetInputs() {}
resetInputs: function() {}
data: {
colors: ['black', 'red', 'white'],
},
main.js
colors: ['black', 'red', 'white']
main.js
index.html
<div class="form-group">
<label>TEXT COLOR</label>
<span v-for="color in colors">
<span class="ml-2">
{{ color }}
</span>
</span>
</div>
<div v-for="(item, index) in array">
<p>{{ item + '-' + index }}</p>
</div>
data: {
array: ['Fist', 'Second', 'Third']
}
html
js
<h1>Students</h1>
<p v-for="student in students">
{{ student.name }}
</p>
data: {
students: [
{ id: 1, name: 'Renan' },
{ id: 2, name: 'Pedro' },
]
}
js
html
:key
<h1>Students</h1>
<p
v-for="student in students"
:key="student.id"
>
{{ student.name }}
</p>
html
<div class="form-group">
<label>TEXT COLOR</label>
<span
v-for="(color, index) in colors"
:key="index"
>
<span class="ml-2">
{{ color }}
</span>
</span>
</div>
index.html
Sintaxe de Objeto
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
Você pode usar camelCase ou kebab-case para o nome da propriedade CSS.
A sintaxe Array para v-bind:style permite que você aplique múltiplos objetos de estilo para o mesmo elemento:
<div :style="[baseStyles, overridingStyles]"></div>
Sintaxe de Array
Sintaxe de Objeto
<div :class="{ active: isActive }"></div>
Podemos passar um objeto para o v-bind:class para alternar classes dinamicamente:
data: {
isActive: true
}
<div class="active"></div>
Que vai renderizar no HTML:
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
Que renderizará:
<div class="active text-danger"></div>
Também é possível utilizar uma expressão ternária
<div :class="[isActive ? activeClass : '']"></div>
<div :class="[activeClass, errorClass]"></div>
Sintaxe de Array
:style="{ color: 'red' }"
Vamos passar a cor para a propriedade do css color.
<div class="form-group">
<label>TEXT COLOR</label>
<span
v-for="(color, index) in colors"
:key="index"
>
<span
id="span-color"
:style="{ background: color }"
>
</span>
</span>
</div>
index.html
#span-color {
border: 1px solid #000;
border-radius: 50%;
cursor: pointer;
display: inline-block;
width: 16px;
height: 16px;
margin-left: 3px;
}
style.css
return { color: this.text.color };
<p :style="textColor">
this.text.color = color;
npm install -g @vue/cli
# OR
yarn global add @vue/cli
Requisito - Node.js
Vue CLI exige Node.js na versão 8.9 ou acima (recomendado 8.11.0 +). Você pode gerenciar múltiplas versões do Node na mesma máquina usando o nvm ou nvm-windows.
Yarn - instalação ubuntu, instalação windows
Para instalar o Vue-CLI
Checar sua versão
vue --version
Vue CLI
? Please pick a preset: (User arrow keys)
> default (babel, eslint)
Manually select features
> vue create meme-generator
yarn serve
<template>
<div>
<!-- html -->
</div>
</template>
<script>
export default {
name: 'ComponentName',
data() {
return {
// data
};
},
methods: {
// methods
},
...
};
</script>
<style>
/* css */
</style>
html
js
css
<template>
<p>{{ hello }}</p>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
hello: 'Hello World!'
}
}
}
</script>
<style scoped>
p {
color: blue;
}
</style>
hello-world.vue
<div id="app">
<hello-world />
</div>
index.html
Vamos criar um componente chamado, meme-generator.vue dentro da pasta components
<template>
<div class="row m-0 py-2 text-center">
<!-- html content -->
</div>
</template>
<script>
export default {
name: 'MemeGenerator',
data() {
return {
title: '',
// data content
};
},
computed: {},
created() {},
methods: {},
};
</script>
<style scoped>
/* style.css */
</style>
meme-generator/src/components/meme-generator.vue
<template>
<div id="app">
<meme-generator />
</div>
</template>
<script>
import MemeGenerator from './components/meme-generator';
export default {
name: 'app',
components: {
MemeGenerator
}
}
</script>
meme-generator/src/App.vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- Bootstrap 4 CSS -->
<link rel="stylesheet" href="https://bootswatch.com/4/lux/bootstrap.min.css">
<!-- Font -->
<link href="https://fonts.googleapis.com/css?family=Passion+One&display=swap" rel="stylesheet">
<title>Meme Generator</title>
</head>
<body>
<noscript>
<strong>
We're sorry but meme-generator doesn't work properly without JavaScript enabled.
Please enable it to continue.
</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
meme-generator/public/index.html
<template>
<div class="form-group">
<label>TEXT COLOR</label>
<span
v-for="(color, index) in colors"
:key="index"
>
<span
id="span-color"
:style="{ background: color }"
>
</span>
</span>
</div>
</template>
<script>
export default {
name: 'TextColor',
};
</script>
<style scoped>
#span-color {
border: 1px solid #000;
border-radius: 50%;
cursor: pointer;
display: inline-block;
width: 16px;
height: 16px;
margin-left: 3px;
}
</style>
<text-color />
meme-generator.vue
<script>
import TextColor from './text-color.vue';
export default {
name: 'MemeGenerator',
components: {
TextColor
},
}
</script>
Propriedades são atributos customizados que você pode registrar em um componente
<script>
export default {
name: 'TextColor',
props: {
colors: {
type: Array,
required: true
},
}
};
</script>
text-color.vue
<text-color :colors="colors" />
meme-generator.vue
props: {
name: {
type: String,
required: true
},
age: {
type: Number,
required: true
},
}
props: {
url: {
type: String,
required: false,
default() {
return '/url';
}
},
canEdit: {
type: Boolean,
required: false,
default() {
return false;
}
},
}
this.$root.$emit('event-name');
Emitir um evento
Ouvir um evento
this.$root.$on('event-name', (data) => {
// do something;
// this.method();
});
source
source
<template>
<div class="form-group">
<label>TEXT COLOR</label>
<span
v-for="(color, index) in colors"
:key="index"
>
<span
id="span-color"
:style="{ background: color }"
@click="emitUpdateTextColor(color)"
>
</span>
</span>
</div>
</template>
<script>
export default {
name: 'TextColor',
props: {
colors: {
type: Array,
required: true
},
},
methods: {
emitUpdateTextColor(color) {
this.$root.$emit('update-text-color', color);
},
},
};
</script>
@click
method
export default {
...,
created() {
this.setTitle();
this.onUpdateTextColor();
},
methods: {
onUpdateTextColor() {
this.$root.$on('update-text-color', (color) => {
this.updateTextColor(color);
})
},
updateTextColor(color) {
this.text.color = color;
}
}
}