22 KiB
ASP.NET Core MVC / Razor Pages: Tematização de UI
Introdução
O ABP Framework fornece um sistema completo de tematização de UI com os seguintes objetivos:
- Módulos de aplicativos reutilizáveis são desenvolvidos de forma independente de tema, para que possam funcionar com qualquer tema de UI.
- O tema de UI é decidido pela aplicação final.
- O tema é distribuído por meio de pacotes NuGet/NPM, para que seja facilmente atualizável.
- A aplicação final pode personalizar o tema selecionado.
Para alcançar esses objetivos, o ABP Framework:
- Determina um conjunto de bibliotecas base usadas e adaptadas por todos os temas. Assim, os desenvolvedores de módulos e aplicativos podem depender e usar essas bibliotecas sem depender de um tema específico.
- Fornece um sistema que consiste em menus de navegação, barras de ferramentas, hooks de layout... que são implementados por todos os temas. Assim, os módulos e a aplicação contribuem para o layout para compor uma UI de aplicação consistente.
Temas Atuais
Atualmente, quatro temas são oficialmente fornecidos:
- O Tema Básico é o tema minimalista com o estilo Bootstrap simples. É open source e gratuito.
- O Tema LeptonX Lite é um tema moderno e elegante de UI Bootstrap. É ideal se você deseja ter um tema de UI pronto para produção. Também é open source e gratuito.
- O Tema Lepton é um tema comercial desenvolvido pela equipe central do ABP e faz parte da licença ABP Commercial.
- O Tema LeptonX também é um tema comercial desenvolvido pela equipe central do ABP e faz parte da licença ABP Commercial. Este é o tema padrão após o ABP v6.0.0.
Também existem alguns temas desenvolvidos pela comunidade para o ABP Framework (você pode pesquisar na web).
Geral
As Bibliotecas Base
Todos os temas devem depender do pacote NPM @abp/aspnetcore.mvc.ui.theme.shared, para que dependam indiretamente das seguintes bibliotecas:
- Twitter Bootstrap como o framework HTML/CSS fundamental.
- JQuery para manipulação do DOM.
- DataTables.Net para grades de dados.
- JQuery Validation para validação do lado do cliente e unobtrusive validation
- FontAwesome como a biblioteca fundamental de fontes CSS.
- SweetAlert para exibir mensagens de alerta e caixas de diálogo de confirmação.
- Toastr para exibir notificações de toast.
- Lodash como uma biblioteca de utilitários.
- Luxon para operações de data/hora.
- JQuery Form para formulários AJAX.
- bootstrap-datepicker para exibir seletores de data.
- Select2 para caixas de seleção/combo melhores.
- Timeago para exibir carimbos de data/hora fuzzy atualizados automaticamente.
- malihu-custom-scrollbar-plugin para barras de rolagem personalizadas.
Essas bibliotecas são selecionadas como as bibliotecas base e estão disponíveis para as aplicações e módulos.
Abstrações / Wrappers
Existem algumas abstrações no ABP Framework para tornar seu código independente de algumas dessas bibliotecas também. Exemplos:
- Tag Helpers facilitam a geração de UIs do Bootstrap.
- As APIs JavaScript Message e Notification fornecem abstrações para usar o Sweetalert e o Toastr.
- O sistema de Forms & Validation manipula automaticamente a validação, então você geralmente não digita diretamente nenhum código de validação.
Os Layouts Padrão
A principal responsabilidade de um tema é fornecer os layouts. Existem três layouts predefinidos que devem ser implementados por todos os temas:
- Application: O layout padrão usado pelas páginas principais do aplicativo.
- Account: Geralmente usado pelo módulo de conta para páginas de login, registro, esqueci minha senha...
- Empty: O layout mínimo que não possui componentes de layout.
Os nomes dos layouts são constantes definidas na classe Volo.Abp.AspNetCore.Mvc.UI.Theming.StandardLayouts.
O Layout de Aplicativo
Este é o layout padrão usado pelas páginas principais do aplicativo. A imagem a seguir mostra a página de gerenciamento de usuários no layout de aplicativo do Tema Básico:
E a mesma página é mostrada abaixo com o layout de aplicativo do Tema Lepton:
Como você pode ver, a página é a mesma, mas a aparência é completamente diferente nos temas acima.
O layout de aplicativo normalmente inclui as seguintes partes:
- Um menu principal
- Uma barra de ferramentas principal com os seguintes componentes:
- Menu do usuário
- Dropdown de troca de idioma
- Alertas de página
- O conteúdo da página (chamado de
RenderBody()) - Hooks de layout
Alguns temas podem fornecer mais partes, como breadcrumbs, cabeçalho e barra de ferramentas da página... etc. Veja a seção Partes do Layout.
O Layout de Conta
O layout de conta é geralmente usado pelo módulo de conta para páginas de login, registro, esqueci minha senha...
Este layout normalmente fornece as seguintes partes:
- Dropdown de troca de idioma
- Área de troca de locatário (se a aplicação for multi-tenant e o locatário atual for resolvido pelo cookie)
- Alertas de página
- O conteúdo da página (chamado de
RenderBody()) - Hooks de layout
O Tema Básico também renderiza a barra de navegação superior para este layout (como mostrado acima).
Aqui está o layout de conta do Tema Lepton:
O Tema Lepton mostra o logotipo do aplicativo e o rodapé neste layout.
Você pode substituir completamente ou parcialmente os layouts do tema em um aplicativo para personalizá-lo.
O Layout Vazio
O layout vazio fornece uma página vazia. Normalmente inclui as seguintes partes:
- Alertas de página
- O conteúdo da página (chamado de
RenderBody()) - Hooks de layout
Implementando um Tema
A Forma Mais Fácil
A forma mais fácil de criar um novo tema é adicionar o módulo Código-fonte do Tema Básico com os códigos-fonte e personalizá-lo.
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic --with-source-code --add-to-solution-file
A Interface ITheme
A interface ITheme é usada pelo ABP Framework para selecionar o layout para a página atual. Um tema deve implementar esta interface para fornecer o caminho do layout solicitado.
Esta é a implementação da ITheme do Tema Básico.
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
{
[ThemeName(Name)]
public class BasicTheme : ITheme, ITransientDependency
{
public const string Name = "Basic";
public virtual string GetLayout(string name, bool fallbackToDefault = true)
{
switch (name)
{
case StandardLayouts.Application:
return "~/Themes/Basic/Layouts/Application.cshtml";
case StandardLayouts.Account:
return "~/Themes/Basic/Layouts/Account.cshtml";
case StandardLayouts.Empty:
return "~/Themes/Basic/Layouts/Empty.cshtml";
default:
return fallbackToDefault
? "~/Themes/Basic/Layouts/Application.cshtml"
: null;
}
}
}
}
- O atributo
[ThemeName]é obrigatório e um tema deve ter um nome único,Basicneste exemplo. - O método
GetLayoutdeve retornar um caminho se o layout solicitado (name) for fornecido pelo tema. Os Layouts Padrão devem ser implementados se o tema for destinado a ser usado por um aplicativo padrão. Ele pode implementar layouts adicionais.
Depois que o tema implementa a interface ITheme, ele deve adicionar o tema às AbpThemingOptions no método ConfigureServices do módulo.
Configure<AbpThemingOptions>(options =>
{
options.Themes.Add<BasicTheme>();
});
O Serviço IThemeSelector
O ABP Framework permite usar vários temas juntos. É por isso que options.Themes é uma lista. O serviço IThemeSelector seleciona o tema em tempo de execução. O desenvolvedor da aplicação pode definir AbpThemingOptions.DefaultThemeName para definir o tema a ser usado ou substituir a implementação do serviço IThemeSelector (a implementação padrão é DefaultThemeSelector) para controlar completamente a seleção do tema em tempo de execução.
Bundles
O sistema de agrupamento fornece uma maneira padrão de importar arquivos de estilo e script nas páginas. Existem dois pacotes padrão definidos pelo ABP Framework:
StandardBundles.Styles.Global: O pacote global que inclui os arquivos de estilo usados em todas as páginas. Normalmente, inclui os arquivos CSS das Bibliotecas Base.StandardBundles.Scripts.Global: O pacote global que inclui os arquivos de script usados em todas as páginas. Normalmente, inclui os arquivos JavaScript das Bibliotecas Base.
Um tema geralmente estende esses pacotes padrão adicionando arquivos CSS/JavaScript específicos do tema.
A melhor maneira de definir novos pacotes é herdar dos pacotes padrão e adicioná-los às AbpBundlingOptions, como mostrado abaixo (este código é do Tema Básico):
Configure<AbpBundlingOptions>(options =>
{
options
.StyleBundles
.Add(BasicThemeBundles.Styles.Global, bundle =>
{
bundle
.AddBaseBundles(StandardBundles.Styles.Global)
.AddContributors(typeof(BasicThemeGlobalStyleContributor));
});
options
.ScriptBundles
.Add(BasicThemeBundles.Scripts.Global, bundle =>
{
bundle
.AddBaseBundles(StandardBundles.Scripts.Global)
.AddContributors(typeof(BasicThemeGlobalScriptContributor));
});
});
BasicThemeGlobalStyleContributor e BasicThemeGlobalScriptContributor são contribuidores de pacotes. Por exemplo, BasicThemeGlobalStyleContributor é definido como mostrado abaixo:
public class BasicThemeGlobalStyleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.Add("/themes/basic/layout.css");
}
}
Em seguida, o tema pode renderizar esses pacotes em um layout. Por exemplo, você pode renderizar os Estilos Globais como mostrado abaixo:
<abp-style-bundle name="@BasicThemeBundles.Styles.Global" />
Consulte o documento Bundle & Minification para entender melhor o sistema de agrupamento.
Partes do Layout
Um layout típico consiste em várias partes. O tema deve incluir as partes necessárias em cada layout.
Exemplo: O Tema Básico tem as seguintes partes para o Layout de Aplicativo
O código do aplicativo e dos módulos só pode mostrar conteúdo na parte de Conteúdo da Página. Se eles precisarem alterar as outras partes (adicionar um item de menu, adicionar um item de barra de ferramentas, alterar o nome do aplicativo na área de marcação...), eles devem usar as APIs do ABP Framework.
As seções a seguir explicam as partes fundamentais pré-definidas pelo ABP Framework e que podem ser implementadas pelos temas.
É uma boa prática dividir o layout em componentes/partials, para que o aplicativo final possa substituí-los parcialmente para fins de personalização.
Marcação
O serviço IBrandingProvider deve ser usado para obter o nome e a URL do logotipo do aplicativo para renderizar na parte de Marcação.
O Modelo de Inicialização do Aplicativo tem uma implementação dessa interface para definir os valores pelo desenvolvedor da aplicação.
Menu Principal
O serviço IMenuManager é usado para obter os itens do menu principal e renderizá-los no layout.
Exemplo: Obter o Menu Principal para renderizar em um componente de visualização
public class MainNavbarMenuViewComponent : AbpViewComponent
{
private readonly IMenuManager _menuManager;
public MainNavbarMenuViewComponent(IMenuManager menuManager)
{
_menuManager = menuManager;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var menu = await _menuManager.GetAsync(StandardMenus.Main);
return View("~/Themes/Basic/Components/Menu/Default.cshtml", menu);
}
}
Consulte o documento Navegação / Menus para saber mais sobre o sistema de navegação.
Barra de Ferramentas Principal
O serviço IToolbarManager é usado para obter os itens da Barra de Ferramentas Principal e renderizá-los no layout. Cada item desta barra de ferramentas é um componente de visualização, então ele pode incluir qualquer tipo de elemento de UI. Injete o IToolbarManager e use o GetAsync para obter os itens da barra de ferramentas:
var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main);
Consulte o documento Barras de Ferramentas para saber mais sobre o sistema de barras de ferramentas.
O tema tem a responsabilidade de adicionar dois itens pré-definidos à barra de ferramentas principal: Seleção de Idioma e Menu do Usuário. Para fazer isso, crie uma classe que implemente a interface IToolbarContributor e adicione-a às AbpToolbarOptions, como mostrado abaixo:
Configure<AbpToolbarOptions>(options =>
{
options.Contributors.Add(new BasicThemeMainTopToolbarContributor());
});
Seleção de Idioma
O item de barra de ferramentas Seleção de Idioma é geralmente um dropdown que é usado para alternar entre idiomas. O ILanguageProvider é usado para obter a lista de idiomas disponíveis e CultureInfo.CurrentUICulture é usado para saber o idioma atual.
O endpoint /Abp/Languages/Switch pode ser usado para alternar o idioma. Este endpoint aceita os seguintes parâmetros de string de consulta:
culture: O idioma selecionado, comoen-USouen.uiCulture: O idioma de IU selecionado, comoen-USouen.returnUrl(opcional): Pode ser usado para retornar uma determinada URL após a troca de idioma.
culture e uiCulture devem corresponder a um dos idiomas disponíveis. O ABP Framework define um cookie de cultura no endpoint /Abp/Languages/Switch.
Menu do Usuário
O menu do usuário inclui links relacionados à conta do usuário. O IMenuManager é usado da mesma forma que o Menu Principal, mas desta vez com o parâmetro StandardMenus.User, como mostrado abaixo:
var menu = await _menuManager.GetAsync(StandardMenus.User);
Os serviços ICurrentUser e ICurrentTenant podem ser usados para obter os nomes do usuário e do locatário atual.
Alertas de Página
O serviço IAlertManager é usado para obter os alertas de página atuais para renderizar no layout. Use a lista Alerts do IAlertManager. Geralmente é renderizado logo antes do conteúdo da página (RenderBody()).
Consulte o documento Alertas de Página para saber mais.
Hooks de Layout
Como o Layout está no pacote do tema, o aplicativo final ou qualquer módulo não pode manipular diretamente o conteúdo do layout. O sistema de Hooks de Layout permite injetar componentes em pontos específicos do layout.
O tema é responsável por renderizar os hooks no local correto.
Exemplo: Renderizar o Hook LayoutHooks.Head.First no Layout de Aplicativo
<head>
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Application)
...
Consulte o documento Hooks de Layout para saber mais sobre os hooks de layout padrão.
Seções de Script / Estilo
Todo layout deve renderizar as seguintes seções opcionais:
- A seção
stylesé renderizada no final dohead, logo antes doLayoutHooks.Head.Last. - A seção
scriptsé renderizada no final dobody, logo antes doLayoutHooks.Body.Last.
Dessa forma, a página pode importar estilos e scripts para o layout.
Exemplo: Renderizar a seção styles
@await RenderSectionAsync("styles", required: false)
Seção de Barra de Ferramentas de Conteúdo
Outra seção pré-definida é a seção de Barra de Ferramentas de Conteúdo, que pode ser usada pelas páginas para adicionar código logo antes do conteúdo da página. O Tema Básico a renderiza da seguinte forma:
<div id="AbpContentToolbar">
<div class="text-end mb-2">
@RenderSection("content_toolbar", false)
</div>
</div>
O id da div de contêiner deve ser AbpContentToolbar. Esta seção deve vir antes do RenderBody().
Recursos de Widgets
O Sistema de Widgets permite definir widgets reutilizáveis com seus próprios arquivos de estilo/script. Todos os layouts devem renderizar o estilo e os scripts do widget.
Estilos de Widget são renderizados da seguinte forma, logo antes da seção styles, após o pacote de estilo global:
@await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
Scripts de Widget são renderizados da seguinte forma, logo antes da seção scripts, após o pacote de script global:
@await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))
Scripts ABP
O ABP tem alguns scripts especiais que devem ser incluídos em todos os layouts. Eles não estão incluídos nos pacotes globais, pois são criados dinamicamente com base no usuário atual.
Os scripts do ABP (ApplicationConfigurationScript e ServiceProxyScript) devem ser adicionados logo após o pacote de script global, como mostrado abaixo:
<script src="~/Abp/ApplicationConfigurationScript"></script>
<script src="~/Abp/ServiceProxyScript"></script>
Título da Página, Item de Menu Selecionado e Breadcrumbs
O serviço IPageLayout pode ser injetado por qualquer página para definir o título da página, o nome do item de menu selecionado e os itens de breadcrumbs. Em seguida, o tema pode usar este serviço para obter esses valores e renderizá-los na UI.
O Tema Básico não implementa este serviço, mas o Tema Lepton implementa:
Consulte o documento Cabeçalho da Página para saber mais.
Troca de Locatário
O Layout de Conta deve permitir ao usuário trocar o locatário atual se a aplicação for multi-tenant e o locatário for resolvido a partir dos cookies. Consulte o Layout de Conta do Tema Básico como um exemplo de implementação.
Classes de Layout
Os Layouts Padrão (Application, Account e Empty) devem adicionar as seguintes classes CSS à tag body:
abp-application-layoutpara o layoutApplication.abp-account-layoutpara o layoutAccount.abp-empty-layoutpara o layoutEmpty.
Dessa forma, os aplicativos ou módulos podem ter seletores com base no layout atual.
RTL
Para oferecer suporte a idiomas da direita para a esquerda, o Layout deve verificar a cultura atual e adicionar dir="rtl" à tag html e a classe CSS rtl à tag body.
Você pode verificar CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft para entender se o idioma atual é um idioma RTL.
O Pacote NPM
Um tema deve ter um pacote NPM que dependa do pacote @abp/aspnetcore.mvc.ui.theme.shared. Dessa forma, ele herda todas as Bibliotecas Base. Se o tema exigir bibliotecas adicionais, ele deve definir essas dependências também.
As aplicações usam o sistema de Gerenciamento de Pacotes do Lado do Cliente para adicionar bibliotecas do lado do cliente ao projeto. Portanto, se uma aplicação usar seu tema, ela deve adicionar a dependência do pacote NPM do seu tema, bem como a dependência do pacote NuGet.





