Desenvolvimento de Aplicações de Página Única com Vue.js

SPA refere-se a uma aplicação web de página única. Neste modelo, o navegador carrega uma única página HTML e atualiza dinamicamente o conteúdo conforme o usuário interage, sem recarregar a página inteira. A navegação é gerenciada pelo lado do cliente, frequentemente utilizando o fragmento de identificador na URL (após o símbolo #), que não dispara uma recarga do navegador.

Por exemplo, uma URL típica de uma aplicação Vue em desenvolvimento pode ser:

http://localhost:8080/#/configuracao/tarefa

A parte após # (o fragmento) define a rota e o componente a ser exibido.

APIs RESTful

As interfaces RESTful são comuns em projetos modernos. Elas mapeiam operações CRUD (Criar, Ler, Atualizar, Deletar) para métodos HTTP específicos:

  • POST para inserir novos dados.
  • GET para recuperar dados.
  • PUT para atualizar dados existentes.
  • DELETE para remover dados.

Por exemplo, considerando o endpoint /api/v1/projetos:

  • GET /api/v1/projetos retorna uma lista de projetos.
  • POST /api/v1/projetos cria um novo projeto.
  • GET /api/v1/projetos/123 obtém o projeto com ID 123.
  • PUT /api/v1/projetos/123 atualiza o projeto 123.
  • DELETE /api/v1/projetos/123 exclui o projeto 123.

Essa abordagem simplifica a definição de endpoints.

Configurando o Ambiente de Desenvolvimento

Instalação do Node.js

Baixe e instale o Node.js do site oficial. Após a instalação, verifique com os comandos:

node -v
npm -v

Se versões forem exibidas, o ambiente está configurado.

Instalação do Vue CLI

O Vue CLI é uma ferramenta para projetos Vue. Instale globalmente:

npm install -g @vue/cli

Crie um novo projeto usando o template webpack:

vue create meu-app

Selecione as opções desejadas durante a configuração. Após a conclusão, entre no diretório e inicie o servidor de desenvolvimento:

cd meu-app
npm run serve

A aplicação estará disponível em http://localhost:8080.

Padrões de Código

Considere adotar um estilo como ESLint com regras específicas, como:

  • Indentação com dois espaços.
  • Uso de aspas simples.
  • Avoidar variáveis redundantes.
  • Ponto e vírgula opcional, dependendo da configuração.

Estrutura do Projeto

Uma estrutura típica após scaffolding inclui:

├── src
│   ├── assets
│   ├── components
│   ├── views
│   ├── router
│   ├── store
│   ├── services
│   ├── App.vue
│   └── main.js
├── public
├── package.json
└── vue.config.js

Organize componentes reutilizáveis em components, páginas em views, e serviços de API em services.

Configurando o Roteamento

Edite src/router/index.js para definir rotas:

import Vue from 'vue'
import VueRouter from 'vue-router'
import PaginaInicial from '../views/PaginaInicial.vue'
import Detalhes from '../views/Detalhes.vue'

Vue.use(VueRouter)

const rotas = [
  {
    path: '/',
    name: 'PaginaInicial',
    component: PaginaInicial
  },
  {
    path: '/detalhes/:identificador',
    name: 'Detalhes',
    component: Detalhes
  }
]

export default new VueRouter({
  routes: rotas
})

O parâmetro :identificador permite rotas dinâmicas.

Integrando uma API com Axios

Instale o Axios:

npm install axios

Crie um serviço de API em src/services/api.js:

import axios from 'axios'

const clienteHttp = axios.create({
  baseURL: '/api/v1',
  timeout: 5000
})

export default {
  obterRecursos(endpoint) {
    return clienteHttp.get(endpoint)
  },
  enviarDados(endpoint, dados) {
    return clienteHttp.post(endpoint, dados)
  },
  atualizarRecurso(endpoint, dados) {
    return clienteHttp.put(endpoint, dados)
  },
  removerRecurso(endpoint) {
    return clienteHttp.delete(endpoint)
  }
}

No main.js, torne o serviço acessível globalmente:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import apiService from './services/api'

Vue.prototype.$api = apiService

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Proxy para APIs em Desenvolvimento

Para evitar problemas de CORS, configure o proxy no vue.config.js:

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
    }
  }
}

Isso redireciona requisições /api para um servidor backend local.

Componentes Vue

Cada arquivo .vue contém template, script e estilo:

<template>
  <div class="componente-exemplo">
    <h2>{{ titulo }}</h2>
    <button @click="incrementar">Contagem: {{ contagem }}</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      titulo: 'Componente de Exemplo',
      contagem: 0
    }
  },
  methods: {
    incrementar() {
      this.contagem++
    }
  }
}
</script>

<style scoped>
.componente-exemplo {
  margin: 1rem;
  padding: 1rem;
  border: 1px solid #ccc;
}
</style>

Renderizando Dados de uma API

No componente PaginaInicial.vue, carregue e exiba dados:

<template>
  <div>
    <Cabecalho></Cabecalho>
    <ul>
      <li v-for="item in listaItens" :key="item.id">
        <router-link :to="`/detalhes/${item.id}`">
          {{ item.nome }}
        </router-link>
        <span>{{ formatarData(item.dataCriacao) }}</span>
      </li>
    </ul>
    <Rodape></Rodape>
  </div>
</template>

<script>
import Cabecalho from '../components/Cabecalho.vue'
import Rodape from '../components/Rodape.vue'
import { formatarData } from '../utils/data'

export default {
  components: { Cabecalho, Rodape },
  data() {
    return {
      listaItens: []
    }
  },
  async created() {
    try {
      const resposta = await this.$api.obterRecursos('projetos')
      this.listaItens = resposta.data
    } catch (erro) {
      console.error('Falha ao carregar projetos:', erro)
    }
  },
  methods: {
    formatarData
  }
}
</script>

Para formatar datas, crie um utilitário em src/utils/data.js:

export function formatarData(dataString) {
  const data = new Date(dataString)
  return data.toLocaleDateString('pt-BR')
}

Página de Detalhes

No componente Detalhes.vue, exiba informações detalhadas:

<template>
  <div v-if="detalhesItem">
    <Cabecalho></Cabecalho>
    <h1>{{ detalhesItem.titulo }}</h1>
    <p>Criado por: {{ detalhesItem.autor }} em {{ formatarData(detalhesItem.dataCriacao) }}</p>
    <div v-html="detalhesItem.conteudo"></div>
    <Rodape></Rodape>
  </div>
</template>

<script>
import Cabecalho from '../components/Cabecalho.vue'
import Rodape from '../components/Rodape.vue'
import { formatarData } from '../utils/data'

export default {
  components: { Cabecalho, Rodape },
  data() {
    return {
      detalhesItem: null
    }
  },
  async created() {
    const id = this.$route.params.identificador
    try {
      const resposta = await this.$api.obterRecursos(`projetos/${id}`)
      this.detalhesItem = resposta.data
    } catch (erro) {
      console.error('Falha ao carregar detalhes:', erro)
    }
  },
  methods: {
    formatarData
  }
}
</script>

Tags: Vue.js SPA RESTful API Axios Vue CLI

Publicado em 6-26 03:23