PROF. Alan Ferreira dos Santos
o nuxt.js
Framework vue
Nuxt.js é um framework de código aberto para aplicações web e é baseado em Vue.js, Node.js, Webpack e Babel.
Foi inspirado no Next.js, que tem estrutura e propósito semelhante, baseado em React.js.
vue
Vue.js é um framework JavaScript criado por um desenvolvedor da Google, que trabalhava no time de desenvolvimento do Angular;
Tem um curva de aprendizado pequena: HTML, CSS e JavaScript;
É versátil, pois você pode trabalhar com o simples e adicionar outras bibliotecas próprias ou de terceiros;
Por fim, é performático, rápido e leve (20k).
webpack
Empacotador
webpack é um empacotador de módulo JavaScript de código aberto.
O webpack pega módulos com dependências e gera conteúdos estáticos representando esses módulos.
Também permite dividir seu código em múltiplos módulos para serem lidos sob demanda.
babel
Transpilador js
O Babel é um transcompilador JavaScript de código aberto, usado principalmente para converter o código ECMAScript 2015+ em uma versão compatível com versões anteriores do JavaScript que pode ser executada por mecanismos JavaScript mais antigos.
criando o app
# usando yarn
yarn create nuxt-app notes-app
# usando npm
npm init nuxt-app notes-app
{
"name": "notes-app",
"version": "1.0.0",
"private": true,
"scripts": {
// inicia servidor de desenvolvimento
"dev": "nuxt",
// constroi a aplicação usando webpack
"build": "nuxt build",
// inicia o servidor de produção
"start": "nuxt start",
// gera um arquivo HTML para cada rota da aplicação
"generate": "nuxt generate"
},
}
package.json
export default {
head: {
title: 'notes-app',
htmlAttrs: {
lang: 'pt-br'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
}
nuxt.config.js
páginas
diretório pages
O diretório pages contém a camada de visualização da aplicação. O Nuxt.js lê todos os arquivos .vue dentro desse diretório e automaticamente cria uma rota para ele dentro do servidor.
<template>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="card bg-warning my-3">
<div class="card-body">
<h5 class="card-title">Título da Nota</h5>
<p class="card-text">
Descrição da nota
</p>
</div>
</div>
</div>
</div>
</div>
</template>
pages/index.vue
<style>
.card {
min-height: 15rem;
}
</style>
pages/index.vue
listar notas
<script>
export default {
data() {
return {
notas: [
{
id: 1,
titulo: "Título da nota",
descricao: "Descrição da nota"
},
{
id: 1,
titulo: "Título da nota 2",
descricao: null
}
]
};
}
};
</script>
pages/index.vue
<template>
<div class="container">
<div class="row">
<div v-for="nota of notas" :key="nota.id" class="col-md-3">
<div class="card bg-warning my-3">
<div class="card-body">
<h5 class="card-title">{{ nota.titulo }}</h5>
<p v-if="nota.descricao" class="card-text">
{{ nota.descricao }}
</p>
</div>
</div>
</div>
</div>
</div>
</template>
pages/index.vue
buscando na api
hooks
O termo hooking descreve uma série de técnicas utilizadas para modificar ou melhorar o comportamento de um sistema operacional, aplicações ou outros componentes de software através da interceptação de chamadas de funções, mensagens ou eventos passados entre componentes de software.
fetch hook
Para carregar dados assíncronos, como dados vindos de uma API, utilizaremos o hook chamado fetch, que acontece após a criação da instância do componente.
Esse hook nos devolverá uma promise, por isso utilizaremos async/await.
export default {
//...
axios: {
baseURL: "https://localhost:4443"
},
};
nuxt.config.js
yarn add @nuxtjs/axios
//ou
npm install @nuxtjs/axios
<script>
export default {
data() {
return {
notas: []
};
},
async fetch() {
this.notas = await this.$axios
.get("nota/usuario/3")
.then(res => res.json());
}
};
</script>
pages/index.vue
$fetchState
O hook fetch também nos permite acessar algumas propriedades durante e após o processamento dos dados, como o estado do processo que está sendo realizado.
<template>
<div class="container">
<p v-if="$fetchState.pending">Carregando...</p>
<p v-else-if="$fetchState.error">Ocorreu um erro :(</p>
<div class="row">
<div v-for="nota of notas" :key="nota.id" class="col-md-3">
<div class="card bg-warning my-3">
<div class="card-body">
<h5 class="card-title">{{ nota.titulo }}</h5>
<p v-if="nota.descricao" class="card-text">
{{ nota.descricao }}
</p>
</div>
</div>
</div>
</div>
</div>
</template>
pages/index.vue
autenticação
módulo auth
O Nuxt possui um módulo próprio que facilita a realização requisições de autenticação.
Com ele podemos configurar autenticações próprias ou ainda autenticações provenientes de serviços como Google, GitHub, entre outros.
Para isso basta instalar a biblioteca e configurar o projeto.
export default {
//...
auth: {
strategies: {
local: {
endpoints: {
login: { url: "login", method: "post" },
user: { url: "usuario", method: "get", propertyName: false },
logout: false
}
}
}
}
};
nuxt.config.js
yarn add @nuxtjs/auth
//ou
npm install @nuxtjs/auth
<script>
export default {
data() {
return {
email: null,
senha: null
};
},
methods: {
async login() {
try {
const response = await this.$auth.loginWith("local", {
data: {
email: this.email,
senha: this.senha
}
});
this.$router.push("/");
} catch (e) {
this.error = e.response.data.message;
}
}
}
};
</script>
pages/login/index.vue
<div class="container-fluid">
<div class="row">
<div class="col-md-7 d-flex vh-100 justify-content-center">
<div class="col-md-5 align-self-center">
<h1 class="text-center mb-5">Notes App</h1>
<p class="text-center">Informe os dados abaixo para acessar</p>
<b-form @submit.prevent="login">
<b-form-group>
<b-form-input
v-model="email"
type="email"
placeholder="E-mail"
required
></b-form-input>
</b-form-group>
<b-form-group>
<b-form-input
v-model="senha"
type="password"
placeholder="Senha"
required
></b-form-input>
</b-form-group>
<b-button block type="submit" variant="primary">Acessar</b-button>
</b-form>
</div>
</div>
<div class="col-md-5 vh-100 cover"></div>
</div>
</div>
pages/login/index.vue
<style>
.cover {
background: url("https://url.gratis/wftZc") center center;
}
</style>
pages/login/index.vue
const jwt = require('jsonwebtoken');
const { secret } = require('../config/security');
module.exports = (req, res, next) => {
const [type, token] = req.headers['authorization'].split(' ');
//...
};
refatorando a API
router.get('/', async (req, res) => {
const [type, token] = req.headers['authorization'].split(' ');
const { id } = jwt.decode(token);
//...
});
auth.js
routes/usuario.js
app.use(
cors({
origin: ['http://localhost:3000'],
})
);
refatorando a API
app.js
em resumo
A biblioteca nuxtjs/auth se encarrega de obter os tokens de autenticação, assim como a interceptação das requisições enviando o token no cabeçalho.
LOGOUT
Assim como temos um método para login, a biblioteca nuxtjs/auth também fornece um método para realizar o logout do usuário.
Quando executado, o método remove do localStorage o token obtido no processo de autenticação.
export default {
//...
auth: {
strategies: {
local: {
endpoints: {
login: { url: "login", method: "post" },
user: { url: "usuario", method: "get", propertyName: false },
logout: false
}
}
}
}
};
nuxt.config.js
<template>
<div>
<b-navbar type="dark" variant="dark">
<b-navbar-brand href="#">Notes App</b-navbar-brand>
<b-navbar-toggle target="navbarNotes"></b-navbar-toggle>
<b-collapse id="navbarNotes" is-nav>
<b-navbar-nav class="ml-auto">
<b-nav-item-dropdown text="User Name" right>
<b-dropdown-item href="#" @click.prevent="logout"
>Sair</b-dropdown-item
>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<div class="container"> </div>
</div>
</template>
index.vue
<script>
export default {
methods: {
async logout() {
await this.$auth.logout();
this.$router.push("/login");
}
}
};
</script>
index.vue
middlewares
diretório middleware
Middlewares permitem que possamos escrever funções customizadas que serão executadas antes da renderização de uma página.
Podem ser configurados globalmente ou direto na página onde será utilizado.
export default function({ store, redirect }) {
if (store.state.auth.loggedIn) {
return redirect("/");
}
}
middleware/auth.js
<script>
export default {
middleware: "auth",
//...
};
</script>
index.vue
200+ recursos
para dev front-end
layouts
diretório layout
Layout é uma ferramenta ótima para alterar o visual de uma aplicação nuxt. Com ele você pode criar layouts distintos para cada tipo de página dentro de um projeto, como login, registro, início e perfil.
layout padrão
Por padrão aplicações vem com um layout padrão criado no diretório layouts. Se um layout não for especificado, a aplicação usará o layout default.vue para renderizar o conteúdo.
componente <nuxt/>
Para criar um novo layout, basta criar um arquivo .vue com o nome desejado no diretório layouts, utilizando a tag <nuxt/> onde será incorporado o conteúdo da página em que utilizaremos o layout.
<template>
<div>
<b-navbar type="dark" variant="dark">
<b-navbar-brand href="/">Notes App</b-navbar-brand>
<b-navbar-toggle target="notesBar"></b-navbar-toggle>
<b-collapse id="notesBar" is-nav>
<b-navbar-nav class="ml-auto">
<b-nav-item-dropdown :text="primeiroNome" right>
<b-dropdown-item href="perfil">Perfil</b-dropdown-item>
<b-dropdown-item href="#" @click.prevent="logout"
>Sair</b-dropdown-item
>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<div class="container">
<Nuxt />
</div>
</div>
</template>
layouts/home.vue
<script>
export default {
computed: {
usuario() {
return this.$store.state.auth.user;
},
primeiroNome() {
const [nome] = this.usuario.nome.split(" ");
return nome;
}
},
methods: {
async logout() {
await this.$auth.logout();
this.$router.push("/login");
}
}
};
</script>
layouts/home.vue
<script>
export default {
layout: "home",
//...
}
</script>
pages/index.vue
alterando os dados do usuário
<template>
<div>
<div class="row">
<div class="col-12">
<h1 class="my-5">Meu Perfil</h1>
<b-card class="p-5">
<div class="row">
<div class="col-md-3 text-center">
</div>
<div class="col-md-9">
</div>
</div>
</b-card>
</div>
</div>
</div>
</template>
pages/perfil/index.vue
<div class="row">
<div class="col-md-3 text-center">
<b-img
center
rounded="circle"
src="https://picsum.photos/125/125/?image=1"
alt="Center image"
/>
<h5 class="mt-3">Nome do caboclo</h5>
</div>
<div class="col-md-9">
<!-- ... -->
</div>
</div>
pages/perfil/index.vue
<div class="row">
<div class="col-md-3 text-center">
<!-- ... -->
</div>
<div class="col-md-9">
<b-form @submit.prevent="save">
<b-form-group label-align="right" label-cols="2" label="Nome">
<b-form-input
v-model="nome"
type="text"
required
></b-form-input>
</b-form-group>
<!-- ... -->
<div class="row">
<div class="col-md-10 offset-md-2">
<b-button type="submit" variant="primary"
>Salvar Perfil</b-button
>
</div>
</div>
</b-form>
</div>
</div>
pages/perfil/index.vue
<script>
export default {
layout: "home",
computed: {
usuario() {
return this.$store.state.auth.user;
}
},
methods: {
async salvar() {
try {
let data = {
nome: this.nome,
email: this.email
};
if (this.senha) {
data = { ...data, senha: this.senha };
}
await this.$axios.put(`usuario`, data);
} catch (e) {
console.log(e);
}
}
}
};
</script>
pages/perfil/index.vue
alterando o stado com auth
<script>
export default {
methods: {
async salvar() {
try {
let data = {
nome: this.nome,
email: this.email
};
if (this.senha) {
data = { ...data, senha: this.senha };
}
const savedUser = await this.$axios.put(`usuario`, data);
await this.$auth.setUser(savedUser.data);
this.$router.push("/");
} catch (e) {
console.log(e);
}
}
}
};
</script>
pages/perfil/index.vue
melhoria de segurança
Para melhorar a segurança de nossa API, vamos extinguir o parâmetro id da rota PUT do recurso usuário. Agora iremos recuperar o id do usuário com base no token que está trafegando nas requisições.
refatorando a API
const jwt = require('jsonwebtoken');
const { secret } = require('../config/security');
module.exports = (req, res, next) => {
if (!req.headers['authorization']) res.status(401).send({ error: 'Token não informado' });
const [type, token] = req.headers['authorization'].split(' ');
jwt.verify(token, secret, (error) => {
if (error) return res.status(401).send({ error });
req.token = token;
next();
});
};
middlewares/auth.js
refatorando a API
router.put('/', async (req, res) => {
try {
const { body, token } = req;
const { id } = jwt.decode(token);
const usuario = await controller.edit(Usuario, body, id);
res.send(usuario);
} catch (error) {
res.status(500).send({ error });
}
});
routes/usuario.js
refatorando a API
const bcrypt = require('bcrypt');
const { saltRounds } = require('../config/security');
module.exports = function (sequelize, DataTypes) {
return sequelize.define(
'usuario',
{
//...
},
{
//...
hooks: {
beforeValidate: (usuario) => {
if(usuario.senha) usuario.senha = bcrypt.hashSync(usuario.senha, saltRounds);
},
},
//...
}
);
};
models/usuario.js
Desafio
Construir uma página para registro dos novos usuários utilizando a funcionalidade layouts do nuxt, coletando Nome, E-mail e Senha.
Ao final, salvar no banco de dados os dados do novo usuário utilizando a API e redirecioná-lo para a página de login após ter finalizado o cadastro.
Para salvar, a rota POST do recurso usuários deverá ser reescrita para que possa ser carregada antes da validação de autenticação da API.
LOCALSTORAGE
para persistir o estado da aplicação
VUEX
É um padrão de gerenciamento de estado/biblioteca para aplicações Vue.js. Com é possível centralizar o armazenamento de todos os componentes da aplicação aplicando regras que garantem que o estado só pode ser mutado de uma forma previsível.
multiplas views dependem de um único estado
ações de diferentes views mudam um único estado
state
Chamada de arvore de estado, é um objeto único que armazena o estado de toda aplicação como uma única fonte da verdade, o que facilita a obtenção de dados instantaneamente e de maneira fácil.
export const state = () => ({
list: []
});
store/nota.js
mutations
A única forma de mudar o estado da aplicação é utilizando uma mutação. São semelhantes a eventos, definidas por um nome e alguns parâmetros, sendo o primeiro referente ao estado, onde realizaremos a modificação e o segundo o valor ou objeto com os dados com as mudanças no estado.
//...
export const mutations = {
SET(state, notas) {
state.list = notas;
}
};
store/nota.js
actions
As ações são responsáveis por solicitar mutações. Isso é feito utilizando a função commit, onde o primeiro parâmetro é o nome da mutação e o segundo o objeto ou valor a ser utilizado pela mutação.
Ações também podem realizar operações assíncronas, local ideal para realizar comunicações com o back-end.
//...
export const actions = {
async list({ commit }, usuarioId) {
try {
const { data } = await this.$axios.get(`nota/usuario/${usuarioId}`);
commit("SET", data);
return data;
} catch (e) {
throw e;
}
}
};
store/nota.js
dispatch
Uma ação pode ser executada por meio do método dispatch por meio da biblioteca global this.$store.
Ele é responsável por receber como parâmetro o nome do módulo/ação a ser realizada, assim como o valor a ser alterado no estado da aplicação.
<script>
export default {
layout: "home",
middleware: "auth",
async fetch() {
await this.$store.dispatch("nota/list", this.usuario.id);
},
computed: {
usuario() {
return this.$store.state.auth.user;
},
notas() {
return this.$store.state.nota.list;
}
}
};
</script>
index.vue
sistema de roteamento
rotas automáticas
Com base na estrutura adotada na pasta pages o Nuxt automaticamente configura as rotas da aplicação.
Algumas regras são importantes para entender a estrutura que será montada pelo framework.
pages/
--| perfil/
-----| index.vue
-----| historico.vue
--| index.vue
diretório pages
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'perfil',
path: '/perfil',
component: 'pages/perfil/index.vue'
},
{
name: 'perfil-historico',
path: '/perfil/historico',
component: 'pages/perfil/historico.vue'
}
]
}
estrutura gerada
rota dinâmicas
undescored
Chamados de dinâmicas as rotas que podem receber parâmetros. Esses parâmetros são identificados por um undescorded no início do aquivo/diretório.
pages/
--| nota
-----| index.vue
-----| _id.vue
--| index.vue
diretório pages
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'nota',
path: '/nota',
component: 'pages/nota/index.vue'
},
{
name: 'nota',
path: '/nota/:id?',
component: 'pages/nota/_id.vue'
},
]
}
estrutura gerada
pages/
--| nota
-----| new.vue
-----| edit/
--------| _id/
-----------| index.vue
--| index.vue
undescored
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'nota-new',
path: '/nota/new',
component: 'pages/nota/new.vue'
},
{
name: 'nota-edit',
path: '/nota/edit/:id',
component: 'pages/nota/edit/_id/index.vue'
},
]
}
estrutura gerada
roteamento manual
Caso prefira o roteamento tradicional, é possível fazer isso configurando a chave router nas configurações da aplicação.
export default {
//...
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'nota-new',
path: '/nota/new',
component: 'pages/nota/new.vue'
},
{
name: 'nota-edit',
path: '/nota/edit/:id',
component: 'pages/nota/edit.vue'
},
]
}
}
nuxt.config.js
Componentes
Reutilizáveis
Componentes são instâncias reutilizáveis do Vue com um nome. Como toda instância Vue, eles também tem acesso a recursos como data, computed, watch, methods e gatilhos de ciclo de vida.
<template>
</template>
<script>
export default {
name: "meu-componente",
props: {
}
};
</script>
<style>
</style>
Single file component
props
propriedades
Props são atributos personalizáveis que você pode registrar em um componente. Quando um valor é passado para um atributo prop, ele torna-se uma propriedade daquela instância de componente.
<template>
<div class="card bg-warning my-5">
</div>
</template>
<script>
export default {
name: "n-nota",
props: {
id: {
type: [String, Number],
required: true
}
},
};
</script>
components/NNota.vue
v-model em compoentes
mão dupla
Você pode usar a diretiva v-model para criar interligações de mão dupla (two-way binding) entre os dados e elementos input, textarea e select de formulários. A diretiva automaticamente busca a maneira correta de atualizar o elemento com base no tipo de entrada.
Isso também é possível em componentes, utilizando a propriedade value no componente.
<template>
<b-input-group class="mb-2">
<b-input-group-prepend is-text>
<!-- -->
</b-input-group-prepend>
<b-form-input
class="bg-warning border-0 text-dark"
:class="{ concluida: value.concluida == 1 }"
placeholder="Novo Item"
v-model="value.descricao"
/>
</b-input-group>
</template>
<script>
export default {
name: "n-checklist-item",
props: {
value: Object
}
};
</script>
COMPONENTS/NCHECLISTITEM.VUE
<template>
<input
:value="value"
@input="$emit('input', $event.target.value)"
/>
</template>
<script>
export default {
name: "n-checklist-item",
props: {
value: Object
}
};
</script>
Elementos nativos
eventos
emissão de valores
Às vezes é útil emitir um valor específico com um evento. Por exemplo, quando nosso usuário pressionar a tecla enter, iremos emitir um evento para confirmar a inclusão do item ao checklist.
<template>
<b-input-group class="mb-2">
<b-input-group-prepend is-text>
<!-- -->
</b-input-group-prepend>
<b-form-input
class="bg-warning border-0 text-dark"
:class="{ concluida: value.concluida == 1 }"
placeholder="Novo Item"
v-model="value.descricao"
@keyup.enter.prevent="change"
/>
</b-input-group>
</template>
<script>
export default {
name: "n-checklist-item",
props: {
value: Object
},
methods: {
async change() {
this.$emit("changeItem", this.value);
}
}
};
</script>
COMPONENTS/NCHECLISTITEM.VUE
<template>
<div>
<ul class="list-unstyled">
<li v-for="(item, index) of value" :key="index">
<n-checklist-item v-model="value[index]"></n-checklist-item>
</li>
<li>
<n-checklist-item
v-model="checklist"
@changeItem="adicionar()"
></n-checklist-item>
</li>
</ul>
</div>
</template>
components/nchecklist.vue
<script>
export default {
name: "n-checklist",
props: {
value: Array
},
data() {
return {
checklist: {
descricao: null,
concluida: 0
}
};
},
methods: {
adicionar() {
this.value.push(this.checklist);
this.checklist = {
descricao: null,
concluida: 0
};
}
}
};
</script>
components/nchecklist.vue
computed
dados computados
Expressões dentro de templates são muito convenientes, mas são destinadas a operações simples. Colocar muita lógica neles pode fazer com que fiquem inchados e que a sua manutenção fique mais complicada.
Para realizar lógicas complexas utilizamos dados computados, que se parecem muito com propriedades definidas no data.
<script>
export default {
name: "n-nota",
data() {
return {
nota: {
id: null,
titulo: null,
descricao: null,
criadoEm: null,
atualizadoEm: null,
checklists: [],
tags: []
}
};
},
computed: {
numeroItensChecklist() {
return this.nota.checklists.length;
}
},
};
</script>
components/nNOTA.vue
watch
oBSERVADORES
Enquanto dados computados são mais adequados na maioria dos casos, há momentos em que um observador personalizado é necessário. Por isso o Vue fornece uma maneira mais genérica para reagir a alterações de dados, o watch. Isto é particularmente útil quando se precisa executar operações assíncronas ou operações complexas antes de responder a uma alteração de dados.
<script>
export default {
data() {
return {
awaitingChange: false,
nota: { }
}
},
watch: {
nota: {
handler(value, oldValue) {
if (!this.awaitingChange) {
setTimeout(() => {
adicionar()
this.awaitingChange = false;
}, 1000);
}
this.awaitingChange = true;
},
deep: true
},
}
};
</script>
COMPONENTS/NNOTA.VUE
Desafio
Construir um componente personalizado onde seja possível categorizar notas utilizando tags.
O componente deverá estar interligado com a propriedade tags do componente NNota.vue, e o controle dessas tags deverá estar dentro do componente construído por você.
Configurando nossa PWA
Progressive Web Apps
PWA é uma metodologia de desenvolvimento considerada uma evolução híbrida entre aplicações web tradicionais e aplicativos móveis, combinando recursos modernos disponíveis nos navegadores e as vantagens de utilizar o celular.
módulo nuxt/pwa
O Nuxt possui um módulo para configurar uma PWA do zero. Com ela é possível:
- Registrar Services Workers;
- Gerar automaticamento o arquivo manifest.json;
- Adiciona automaticamente os metadados amigáveis do SEO com a integração manifesto;
- Gera automaticamente ícones de aplicativos com diferentes tamanhos;
- Permite utilizar notificações push com o OneSignal.
yarn add --dev @nuxtjs/pwa
Instalação
{
buildModules: [
'@nuxtjs/pwa',
]
}
nuxt.config.js
sw.*
.gitignore
Módulo de ícone
{
pwa: {
icon: {
source: "static/icon.png"
},
}
}
nuxt.config.js
módulo meta
{
pwa: {
//...
meta: {
theme_color: "#fff"
},
}
}
nuxt.config.js
módulo manifest
{
pwa: {
//...
manifest: {
// Presente em telas de diálogo de instalação, WebStores
name: 'Notes App TADS',
// Tela iniciais do dispositivo, Novas abas
short_name: "Notes App"
// Recomendado pela Google
description: 'Aplicativo de Notas da Aula de Programação Web'
lang: 'pt-br',
// Equivalente a meta tag theme-color
theme_color: "#fff"
}
}
}
nuxt.config.js
módulo workbox
Bibliotecas JS para PWA
É uma coleção de bibliotecas Java Script para PWA's. Esse módulo adiciona suporte completo para aplicações offline.
Permite configurar por exemplo como sua aplicação irá realizar o cache das informações, rotas, etc.
O Nuxt já realiza algumas configurações padrões que podem ser sobrescritas.
helpers
ajudantes
Helpers são ajudantes presentes no Nuxt. O Ajudante $nuxt está presente no Nuxt para melhorar a experiência dos usuários.
<template>
<div>
<!--
...
-->
<div class="container">
<b-alert class="mt-5" variant="dark" show v-if="$nuxt.isOffline"
>Você está offline</b-alert
>
<Nuxt />
</div>
</div>
</template>
layouts/home.vue
// Verifica se está desconectado
this.$nuxt.isOffline
window.$nuxt.isOffline
// Verifica se está conectado
this.$nuxt.isOnline
window.$nuxt.isOnline
módulo One Signal
envio de mensagens
O OneSignal é uma ferramenta para envio de mensagens de diversos tipos, como Mobile Push e Web Push.
Configurar o módulo OneSignal para PWAs Nuxt, permite integração rápida com essa ferramenta.
yarn add @nuxtjs/onesignal
instalação
{
//...
modules: [
//...
'@nuxtjs/onesignal'
]
}
NUXT.CONFIG.JS
{
//...
oneSignal: {
init: {
appId: 'YOUR_APP_ID',
allowLocalhostAsSecureOrigin: true,
cdn: true,
welcomeNotification: {
disable: true
}
}
}
}
NUXT.CONFIG.JS
meta tags e seo
seo para SPA's
O Nuxt oferece recursos que facilitam a otimização de páginas para motores de busca. As tags meta podem ser definidas de duas formas.
global
Muito útil para adicionar um título padrão e tag de descrição para fins de SEO ou para definir o viewport ou adicionar o favicon.
{
head: {
title: "Notes App",
htmlAttrs: {
lang: "pt-br"
},
bodyAttrs: {
class: "bg-light"
},
meta: [
{ charset: "utf-8" },
{ name: "viewport", content: "width=device-width, initial-scale=1" },
{
hid: "description",
name: "description",
content: "Sem lojas e instalações. Crie suas anotações mesmo offline"
}
],
link: [{ rel: "icon", type: "image/png", href: "/icon.png" }]
},
}
nuxt.config.js
local
Também é possível adicionar títulos e meta para cada página usando o método dentro de sua tag de script em cada página utilizando o head.
<script>
export default {
head: {
title: 'Login',
meta: [
{
hid: 'description',
name: 'description',
content: 'Acesse o Notes App'
}
],
}
}
</script>
pages/login.vue
hora do código
Configurar o head para todas as páginas do projeto:
- Registro - Notes App;
- Home - Notes App;
- Perfil - Notes App;
- Nova Nota - Notes App;
- Alterar Nota - Notes App.
desafio 07/06
Implementar as seguintes adequações na edição de Notas para quando a aplicação estiver offline:
- Carregar o conteúdo da Nota do estado ao carregar o modo de edição;
- Na ação de atualização, utilizar somente o estado para guardar as alterações.
transições
transições
Transições permitem aplicar regras de css como animações e transições.
classes de transição
v-enter: Inicia o estado de entrada. Aplicada antes do elemento ser inserido, removida depois de um frame.
v-enter-active: Ativa e termina o estado de entrada. Aplicada antes do elemento ser inserido, removida quando a transição/animação termina.
v-leave-active: Estado ativo de saída. Aplicada durante toda a fase de saída. Adicionada imediatamente quando a transição de saída é disparada, removida quando a transição/animação termina. Esta classe pode ser usada para definir a duração, atraso e a curva da transição de saída.
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
assets/css/main.css
<script>
export default {
transition: "fade"
}
</script>
pages/login.vue
{
//...
pageTransition: "fade",
}
nuxt.config.js
Nuxt.js
By Alan Ferreira dos Santos
Nuxt.js
- 537