Blazor - Sítio do Zecão
Hoje vamos criar uma aplicação Blazor para mostrar alguns recursos como a interoperabilidade JavaScript e o tratamento de imagens de áudio. |
Hoje vamos criar um aplicação Blazor que vai tratar com a interoperabilidade Javascript para emitir sons, e, como exemplo vamos criar um galeria de imagens de animais que costumam ser encontrados em um sítio onde cada animal vai ter uma breve descrição e onde poderemos ouvir o som característico do animal.
Neste projeto vamos usar imagens de animais e arquivos de áudio no formato WAV onde para cada animal teremos o respectivo arquivo de áudio com o som característico do animal.
As imagens dos animais foram obtidos da internet e os arquivos de áudio podem ser obtidos no seguinte endereço : http://audiocidades.utopia.org.br/biblioteca/biblioteca_sons_animais.html
Criando o projeto no VS 2022
Abra o VS 2022 e clique em New Project e a seguir selecione o template Blazor Server App e informe o nome SitioApp :
A seguir defina as configurações conforme abaixo e clique em Create:
Vamos limpar o projeto removendo os componentes Counter.razor, FetchData.razor, SurveyPrompt.razor e o conteúdo da pasta Data do projeto.
No arquivo Index.razor vamos definir o código abaixo que vai ser a página de apresentação da aplicação e que vai exibir apenas uma imagem:
@page "/"
<PageTitle>Index</PageTitle>
<h1>Sitio do Zecão</h1>
<hr />
<img src="/sitio/caipira2.jpg" />
|
No arquivo NavMenu.razor vamos ajustar o código para exibir dois itens no menu: Sitio e Animais
.. <div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> <nav class="flex-column"> <div class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> Sítio </NavLink> </div> <div class="nav-item px-3"> <NavLink class="nav-link" href="/sitio"> <span class="oi oi-plus" aria-hidden="true"></span> Animais </NavLink> </div> </nav> </div> .. |
Vamos criar na pasta wwwroot do projeto as seguintes pastas:
Na pasta Data do projeto vamos criar a classe Animal com o código:
namespace SitioApp.Data;
public class Animal public sealed record AnimalInfo(string Nome, string Descricao) |
A classe Animal define o método GetAll que retorna uma lista contendo o nome e uma breve descrição sobre o animal. Aqui estamos usando o tipo record para produzir as propriedades ImagemUrl e WavUrl que estão sendo geradas a partir da pasta images e audio respectivamente a partir de onde montamos o caminho da imagem e do respectivo arquivo de áudio.
Aqui estamos simplificando o código e não estamos usando um banco de dados para armazenar as informações. (Fique a vontade para incrementar o projeto.)
No arquivo _Imports.razor vamos definir o código que será usado pelos componentes:
@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using SitioApp @using SitioApp.Shared @using SitioApp.Data |
A seguir vamos criar na pasta Pages o componente Sitio.razor com o código abaixo:
@page "/sitio"
<h3> <div class="container-fluid"> |
Este componente vamos obter a lista de animais definida na classe Animal e resolver os valores das propriedades Nome, ImagemUrl e do arquivo de áudio e descrição.
Criando o componente Animais
Na pasta Shared do projeto crie o componente Animais.razor com código a seguir:
@inject IJSRuntime Js @implements IDisposable
<div class="col-3 d-flex pb-3"> @code { bool EmExecucao { get; set; } [Parameter] [Parameter] [Parameter] [Parameter] private DotNetObjectReference<Animais>? animal; private ElementReference Audio { get; set; } private async Task ExecutarAudio() private async Task PararAudio() [JSInvokable] protected override async Task OnAfterRenderAsync(bool firstRender) public void Dispose() |
Vamos entender o código:
No inicio estamos injetando uma dependência IJSRuntime, que nos permitirá interagir com elementos JavaScript e DOM do lado do cliente. Veremos a variável Js usada posteriormente em nosso bloco @code.
A seguir estamos usando um Card do Bootstrap para exibir a imagem, o titulo e estamos usando @childContent e o recurso RenderFragment para obter o conteúdo do componente filho Animal e obter os valores das propriedades.
Nota: No Blazor quando definimos uma marcação dentro de um componente, ele vai assumir que deve ser atribuído a um parâmetro no componente que descende da classe RenderFragment e é chamado ChildContent.
Criamos dois botões de comando onde usamos os eventos onclick para executar e parar o áudio através dos métodos ExecutarAudio e PararAudio.
Definimos a tag HTML audio onde usamos o atributo @ref com o tipo ElementReference. O tipo nos permite manter uma referência DOM a um elemento HTML; vamos usá-lo para passar nossa tag de áudio para nosso JavaScript para reproduzir e parar o som de nossos animais.
Nota: Quando precisamos de uma referência a um elemento HTML, devemos decorar esse elemento (ou componente Blazor) com @ref. Identificamos qual membro em nosso componente manterá uma referência ao elemento HTML criando um membro com o tipo ElementReference e o identificamos no elemento usando o atributo @ref.
No nosso projeto, o atributo @ref mapeia diretamente para nossa propriedade privada Audio.
Nos métodos ExecutarAudio e PararAudio estamos usando o IJSRuntime e estamos interagindo com o nosso elemento audio DOM e portanto usamos a propriedade Js para invocar nossas funções Javascript. Assim esses métodos são responsáveis por gerenciar o estado de EmExecucao alternando o valor para true ou false.
Outro atributo essencial para lidar com a interoperabilidade do JavaScript é o JsInvokeAttribute.
O InvokeVoidAsync no IJSRuntime permite chamar funções JavaScript sem esperar nenhum valor de retorno. Essas funções devem estar disponíveis na variável global window. O primeiro parâmetro de InvokeVoidAsync é a função JavaScript que você deseja invocar. Você pode passar tantos parâmetros subsequentes e eles serão passados para a função JavaScript. Os ElementReferences passados para InvokeVoidAsync serão convertidos automaticamente para o HTMLElement.
Este recurso permite que nosso JavaScript do lado do cliente chame um método .NET usando SignalR. Criamos essa ponte usando a classe DotNetObjectReference e precisamos criar a referência em nosso método OnAfterRenderAsync porque nosso componente é acessível.
Nota: Para chamar um método em uma instância de objeto .NET, primeiro precisamos passar uma referência ao objeto para JavaScript. Não podemos passar nosso objeto diretamente porque queremos fornecer ao JavaScript uma referência ao nosso objeto em vez de uma representação serializada Json de seu estado e fazemos isso criando uma instância da classe DotNetObjectReference.
Agora vamos tratar das funções Javascript que vamos usar em nosso projeto.
Usar o Blazor significa escrever menos Javascript mas se precisar podemos usar a interoperabilidade do Blazor com o JavaScript e assim melhorar a interface com usuário usando recursos Javascript. Se você é daqueles que procura evitar JavaScript completamente, lamento dizer mas isso às vezes não será possível.
Felizmente, no contexto do nosso projeto vamos precisar usar um JavaScript mínimo. Vamos criar um novo arquivo audio.js JavaScript dentro da pasta /wwwroot/js/ e colar as seguintes funções no arquivo :
function initAudio(element, reference){ element.addEventListener("ended", async e => { await reference.invokeMethodAsync("OnEnd"); }); } function executarAudio(element) { function pararAudio(element) { |
Neste código
estamos interagindo com nossos elementos de referência encontrados em nosso
componente. Essa é a verdadeira magia do Blazor, permitindo interações perfeitas
de servidor e cliente com muito pouco código.
Em seguida, precisaremos referenciar este script em nosso arquivo
_Layout.cshtml, localizado no diretório
Pages acima da referência ao
blazor.server.js :
...
<body> |
Agora é só alegria...
Executando o projeto teremos o seguinte resultado:
Clicando no menu Animais teremos a exibição do componente Sitio.razor que vai utilizar o componente Animais.razor :
Para ouvir o áudio basta clicar no botão de comando...
Pegue o projeto aqui: SitioApp.zip (sem as referências)
"O ímpio tem
muitas dores, mas àquele que confia no Senhor a misericórdia o cercará."
Salmos 32:10
Referências: