Vue.js é um framework JavaScript voltado para a criação de interfaces de usuário dinâmicas. Ele é leve, flexível e pode ser integrado de maneira gradual em projetos já existentes, sem precisar reestruturar completamente o código. Sua simplicidade, aliada à sua capacidade de gerenciar o estado de componentes, torna-o uma escolha popular para desenvolvedores que buscam uma abordagem moderna para a criação de interfaces.

Neste exemplo, estamos criando aplicativos ASP.NET Core MVC que renderizam páginas HTML, e utilizaremos o Vue.js para a manipulação dos elementos dinâmicos nessas páginas. Ao fazer isso, estamos optando por uma alternativa mais moderna ao tradicional jQuery, aproveitando os recursos avançados de frameworks como Vue.js para lidar com interatividade e reatividade.

Esse post pretende ser educacional e não apresenta um código pronto para produção, mas sim um guia para ajudar no entendimento de como integrar o Vue.js com o ASP.NET Core MVC.

Vamos começar criando a pasta raiz para nosso projeto e uma solution:

mkdir AspNetCoreMvcVueJs
dotnet new sln

Agora, vamos criar um projeto MVC e adicioná-lo à nossa solution:

dotnet new mvc -n MyApp
dotnet sln add MyApp/MyApp.csproj

Vamos adicionar a importação do Vue.js usando importmap, uma maneira moderna de importar bibliotecas JavaScript diretamente do CDN, sem a necessidade de um gerenciador de pacotes. Isso facilita a integração do Vue.js com o ASP.NET Core MVC.

Abra o arquivo _Layout.cshtml na pasta Views/Shared e insira o seguinte código para importar o Vue.js:

    @* Add Vue *@
    <script type="importmap">
        {
          "imports": {
            "vue": "https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.21/vue.esm-browser.prod.min.js"
          }
        }
    </script>

Mixins no Vue.js são uma poderosa ferramenta que permite reutilizar lógica entre diferentes componentes de uma aplicação. Eles contêm opções reutilizáveis, como métodos, variáveis reativas, ou hooks do ciclo de vida, que podem ser incluídos em múltiplos componentes Vue. Isso facilita a manutenção e a organização do código, especialmente quando temos funcionalidades comuns que precisam ser implementadas em várias partes da aplicação.

Quando um mixin é aplicado a um componente, todas as suas propriedades e métodos são mesclados ao componente. Isso significa que o componente poderá acessar qualquer função ou dado definido no mixin como se tivesse sido declarado diretamente no próprio componente. É uma excelente solução para evitar repetição de código, tornando o desenvolvimento de aplicações mais dinâmico e eficiente.

No arquivo _Layout.cshtml, criamos um componente Vue principal e utilizamos mixins para tornar a lógica mais modular e reutilizável:

@* Vue app *@
<script type="module">
    import { createApp } from 'vue';
    
    const app = createApp({
        mixins: [pageMixin]
    });

    app.mount('#app');
</script>

Com isso, podemos criar nossa primeira página. No arquivo Views/Home/Index.cshtml, substitua o conteúdo pelo seguinte código:

@{
    ViewData["Title"] = "Counter";
}

<div class="text-center">
    <h1>Simple Counter</h1>
    <div id="app">
        <h2>{{ count }}</h2>
        <div class="d-flex justify-content-center gap-2">
            <button v-on:click="increment" class="btn btn-primary">Increment</button>
            <button v-on:click="decrement" class="btn btn-danger">Decrement</button>
        </div>
    </div>
</div>

@section Scripts {
    <script>
        const pageMixin = {
            data() {
                return {
                    count: 0
                };
            },
            methods: {
                increment() {
                    this.count++;
                },
                decrement() {
                    this.count--;
                }
            }
        };
    </script>
}
  • O Vue.js é utilizado para criar uma instância reativa de dados, controlando o comportamento do contador na interface.
  • A propriedade data() do Vue.js retorna um objeto que contém o estado inicial, no caso, a variável count, que começa com o valor 0.
  • O Vue.js faz a vinculação reativa de dados (data binding) entre a variável count e o conteúdo do elemento <h2>. Isso significa que sempre que o valor de count for alterado, a interface será automaticamente atualizada para refletir essa mudança.
  • Os métodos increment() e decrement() são definidos dentro da propriedade methods do Vue.js. Esses métodos alteram o valor da variável count ao serem chamados.

O uso da diretiva v-on:click no Vue.js permite a vinculação dos eventos de clique dos botões aos métodos increment() e decrement(), atualizando o valor de count dinamicamente quando o usuário interage com os botões.

Vamos executar a aplicação e verificar o comportamento da página:

dotnet run

Tudo correu com esperado!

Agora, vamos criar uma nova página em nossa aplicação ASP.NET Core MVC chamada Components.cshtml, onde utilizaremos componentes do Vue.js. Isso permitirá que você veja como trabalhar com componentes reutilizáveis em uma página da aplicação.

Para começar, precisamos criar um componente Vue.js que será utilizado em nossa nova página. Vamos criar uma pasta chamada components dentro de wwwroot/js e, dentro dessa pasta, criaremos um arquivo chamado countComponent.js com o seguinte código:

export default {
    data() {
        return {
            count: 0
        };
    },
    template: `
    <button @click="count++">
      You clicked me {{ count }} times.
    </button>`
}

Este componente utiliza JavaScript nativo para manipular o contador e renderiza um botão que exibe o número de vezes clicado. Ao clicar no botão, o valor de count é incrementado. O componente foi escrito em JavaScript nativo, sem o uso de ferramentas de compilação como Babel ou Webpack, que são frequentemente utilizados em projetos mais complexos.

Existem dois tipos de componentes Vue.js: os compilados e os não compilados.

  1. Componentes Não Compilados: esses componentes são escritos diretamente em JavaScript, como no exemplo acima. Eles podem ser usados sem a necessidade de um ambiente de build ou ferramentas de compilação. Esta abordagem é simples, mas limitada quando o projeto cresce e a complexidade aumenta.
  2. Componentes Compilados: esses componentes são escritos em arquivos .vue e passam normalmente por uma etapa de compilação usando ferramentas como Vue CLI, Vite, ou Webpack. Essa abordagem permite dividir o template, script, e estilos em uma única estrutura modular, oferecendo mais organização e flexibilidade.

Para projetos mais complexos, os componentes compilados são geralmente preferidos devido à escalabilidade e manutenção que eles oferecem. No entanto, para pequenos exemplos como este, o uso de componentes não compilados funciona bem e é fácil de configurar.

Com o componente criado, agora podemos adicionar o conteúdo à nova página Components.cshtml. Substitua o conteúdo dessa página pelo seguinte código:

@{
ViewData["Title"] = "Counter";
}

<div class="text-center">
    <h1>Components</h1>
    <div class="d-flex justify-content-center gap-2">
        <count-component></count-component>
        <count-component></count-component>
        <count-component></count-component>
    </div>
</div>

@* Create mixin *@
@section Scripts {
    <script>
        const pageMixin = {};
    </script>
}
  • Três Instâncias do Componente: Cada count-component tem seu próprio estado isolado, permitindo que os contadores operem independentemente.
  • Uso de Vue.js com Componentes: Demonstramos como usar componentes Vue.js não compilados diretamente em uma página ASP.NET Core MVC.

Finalmente, na controladora do seu projeto ASP.NET Core, adicione uma nova ação chamada Components para renderizar a nova página:

public IActionResult Components()
{
    return View();
}

Para garantir que o componente Vue.js esteja disponível em todas as páginas que utilizam o layout principal, precisaremos modificar o arquivo _Layout.cshtml para importar e registrar o componente.

Primeiro, vamos adicionar o script que importa o componente countComponent.js no layout principal. Isso garante que o componente estará disponível para uso em qualquer página que herde deste layout.

@* Components *@
<script src="~/js/components/countComponent.js" asp-append-version="true" type="module"></script>

Essa linha importa o script do componente diretamente da pasta wwwroot/js/components e garante que ele seja carregado corretamente com a versão mais recente, graças à tag asp-append-version.

Agora, vamos modificar o código de criação do aplicativo Vue.js dentro do _Layout.cshtml, passando o componente criado para que ele possa ser utilizado em qualquer página que utilize o layout.

Substitua ou adicione o seguinte código para criar o aplicativo Vue.js e registrar o componente CountComponent:

@* Vue app *@
<script type="module">
    import { createApp } from 'vue';
    import CountComponent from '@Url.Content("/js/components/countComponent.js")';
    
    const app = createApp({
        mixins: [pageMixin],
        components: {
            // Registrar o componente aqui
            'count-component': CountComponent
        }
    });

    app.mount('#app');
</script>

Nesse código, importamos o CountComponent e o registramos localmente dentro do aplicativo Vue.js. Agora, sempre que a tag <count-component> for usada em uma página que herda do _Layout.cshtml, o componente será renderizado corretamente.

Vamos executar novamente a aplicação e verificar a nova página criada:

Podemos clicar em cada componente e verificar que cada um possui seu próprio estado e seus próprios event handlers.

Agora vamos criar uma nova página chamada Forms.cshtml, onde manipularemos dois tipos de formulários: um gerenciado pelo Vue.js no frontend e outro gerenciado pelo ASP.NET Core mediante uma requisição POST. Isso nos permite interagir com dados no frontend, enquanto os submetemos ao backend para processamento e persistência.

Estrutura da Página Forms.cshtml:

@model MyApp.ViewModels.ItemsViewModel

@{
    ViewData["Title"] = "Forms";
}

<div class="text-center">
    <h1>Forms</h1>
</div>

<!-- Formulário Vue.js -->
<form v-on:submit.prevent="addItem">
    <div class="form-group">
        <p>Item name: <input class="form-control" type="text" required v-model="itemName"></p>

        <div v-show="items.length > 0">
            <p>Items:</p>
            <ul>
                <li v-for="item in items">{{ item }}</li>
            </ul>
        </div>

        <button class="btn btn-secondary" type="submit">Add item</button>
    </div>
</form>

<!-- Formulário ASP.NET Core -->
<form asp-action="Forms" method="post">
    <input type="hidden" asp-for="Items" :value="concatenatedItems" />
    <button class="btn btn-primary mt-2">Save</button>
</form>

@section Scripts {
    <script>
        const pageMixin = {
            data() {
                return {
                    itemName: null,
                    items: []
                };
            },
            computed: {
                concatenatedItems() {
                    return this.items.join(';');
                }
            },
            methods: {
                addItem() {
                    this.items.push(this.itemName);
                    this.itemName = null;
                }
            }
        };

        const app = Vue.createApp({
            mixins: [pageMixin]
        });

        app.mount('body');
    </script>
}
  • Vue.js Form:O formulário gerenciado pelo Vue.js permite adicionar itens a uma lista de forma dinâmica, sem fazer uma requisição ao servidor.Cada item inserido no campo de texto é adicionado à lista de itens exibida abaixo do formulário.O botão "Add item" utiliza o método addItem para atualizar a lista items.O campo de texto é limpo após cada submissão, e a lista é exibida apenas quando há itens adicionados.
  • ASP.NET Core Form:O segundo formulário utiliza a estrutura padrão do ASP.NET Core, enviando os dados para a ação Forms via uma requisição POST.O campo oculto (<input type="hidden">) envia a lista de itens concatenada como uma string, separada por ;, ao backend.Ao clicar no botão "Save", o formulário é submetido para o servidor, permitindo o processamento ou salvamento dos dados.

Criamos um ViewModel simples para transportar a lista de itens concatenada como uma única string para o servidor:

namespace MyApp.ViewModels
{
    public class ItemsViewModel
    {
        public string? Items { get; init; }
    }
}

A controladora FormsController gerencia a exibição da página e o processamento do formulário enviado via POST. Aqui está como a controladora deve ser estruturada:

public class FormsController : Controller
{
    // Exibe a página do formulário
    public IActionResult Forms()
    {
        return View();
    }

    // Processa os dados enviados via POST
    [HttpPost]
    public IActionResult Forms(ItemsViewModel viewModel)
    {
        if (ModelState.IsValid)
        {
            // Redireciona para outra ação, como a página inicial, após o processamento bem-sucedido
            return RedirectToAction(nameof(Index));
        }

        // Se houver falha na validação, retorna à mesma view com os dados atuais
        return View(viewModel);
    }
}

Com isso, podemos testar a página:

a

a

Clicando em "Save", podemos analisar o view model enviado a controladora:

E é isso pessoal!

Esse foi um simples exemplo de como podemos integrar o ASP.NET Core MVC ao Vue.js.

Você já pode baixar o projeto por esse link, e não esquece de me seguir no LinkedIn!

Até a próxima, abraços!

💡
Podemos te ajudar com uma revisão 100% gratuita do seu ambiente cloud.
Share this post