如何將現有的`Blazor`專案的主題切換寫的更好看?

2023-08-28 15:00:55

如何將現有的Blazor專案的主題切換寫的更好看?

在現有的系統當中,我們的主題切換會比較生硬,下面我們將基於Masa Blazor實現好看的擴散主題切換的樣式效果。

安裝MASA.Template

dotnet new install MASA.Template

建立Masa Blazor專案

開啟vs2022

選擇server app模板

開啟wwwroot/css/site.css

新增一下程式碼,這個程式碼是核心樣式實現。 animation: clip .5s ease-in;的.5s則是擴散時間。


::view-transition-old(root) {
    animation: none;
}
::view-transition-new(root) {
    mix-blend-mode: normal;
    animation: clip .5s ease-in;
}

@keyframes clip {
    from {
        clip-path: circle(0% at var(--x) var(--y));
    }
    to{
        clip-path: circle(100% at var(--x) var(--y));
    }
}

開啟Pages/_Host.cshtml

新增以下程式碼,請新增到body的內部的最尾部的位置。

    <script>
        window.switchTheme = function (dotNetHelper, x, y) {
            document.documentElement.style.setProperty('--x', x + 'px')
            document.documentElement.style.setProperty('--y', y + 'px')
            document.startViewTransition(() => {
                dotNetHelper.invokeMethodAsync('SwitchTheme');
            });
            
        }
    </script>

這個方法向window新增一個switchTheme的js方法,需要傳遞呼叫的範例,x,y則是擴散的開始位置,

然後會建立一個css的變數,這個變數對應到上面的clip裡面的var(--x)和var(--y)

開啟Shared\MainLayout.razor,修改成以下程式碼

@inherits LayoutComponentBase
@inject GlobalConfig GlobalConfig
@inject IJSRuntime JsRuntime
@inject MasaBlazor MasaBlazor

<MApp >
    <PPageTabsProvider>
        <CascadingValue Value="GlobalConfig.Culture.Name" Name="CultureName">
            <MAppBar  Elevation=0 App Height="100" Class="default-app-bar mx-6">
                 <div class="default-app-bar__actions @PageModeClass">
                     <Favorite />
                     <MSpacer />
                     <Search />
                     <MIcon Size=20 Class="ml-5" Color="neutral-lighten-3">mdi-message-processing-outline</MIcon>
                     <MIcon Size=20 Class="ml-5" Color="neutral-lighten-3" OnClick="() => _showSetting = true">mdi-cog-outline</MIcon>
                     <Language OnLanguageChanged="OnLanguageChanged" />
                     <MButton OnClick="ClickSwitchTheme">切換</MButton>
                     <Login />
                 </div>
                 <div class="default-app-bar__nav @PageModeClass">
                     @if (_pageTab == PageModes.PageTab)
                    {
                        <PageTabs @ref="_pageTabs" SelfPatterns="@s_selfPatterns" />
                    }
                    else
                    {
                        <Breadcrumb />
                    }
                </div>
            </MAppBar>

            <Navigation />

            <MMain Class="fill-lighten-1">
                <div class="pa-6">
                    @if (_pageTab == PageModes.PageTab)
                    {
                        <PPageContainer PageTabs="@_pageTabs?.PPageTabs" SelfPatterns="@s_selfPatterns">
                            @Body
                        </PPageContainer>
                    }
                    else
                    {
                        @Body
                    }
                </div>
            </MMain>
            <Settings @bind-PageModel="_pageTab" @bind-Show=_showSetting />
        </CascadingValue>
    </PPageTabsProvider>
</MApp>

@code {

    private DotNetObjectReference<MainLayout>? objRef;

    private bool dark = false;

    private static readonly string[] s_selfPatterns =
    {
        "/app/todo"
    };

    private bool? _showSetting;

    private string? _pageTab;

    private PageTabs? _pageTabs;

    private string PageModeClass => _pageTab == PageModes.PageTab ? "page-mode--tab" : "page-mode--breadcrumb";

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            await GlobalConfig.InitFromStorage();
        }
    }

    void OnLanguageChanged(CultureInfo culture)
    {
        GlobalConfig.Culture = culture;
    }

    private void ClickSwitchTheme(MouseEventArgs args)
    {
        _ = JsRuntime.InvokeVoidAsync("switchTheme", objRef, args.ClientX, args.ClientY);
    }

    [JSInvokable]
    public void SwitchTheme()
    {
        dark = !dark;
        MasaBlazor.ToggleTheme();
    }

}

在這裡我們提供了SwitchTheme用於提供個js呼叫從而切換主題。

我們在原有的基礎上新增了一個按鈕,並且這個按鈕點選會觸發ClickSwitchTheme事件,然後通過JsRuntim呼叫js的方法,並且將當前範例傳遞到js,args.ClientX,args.ClientY則是點選的位置,我們會用點選的位置作為擴散的位置。

下面是執行效果,由於Masa Pro並沒有適配暗夜效果,所以看的並不明顯。如果你想看到更好的效果可以檢視open666.cn

這是使用的簡單Demo的效果。

技術交流群:

BlazorQQ群:452761192

來自token的分享。