Blazor如何實現類似於微信的Tab切換?

来源:https://www.cnblogs.com/hejiale010426/archive/2023/01/23/17064872.html
-Advertisement-
Play Games

是否有小伙伴在使用tab的時候想進行滑動切換Tab? 並且有滑動左出左進,右出右進的效果 ,本文將講解怎麼在Blazor中去通過滑動切換Tab 本文中的UI組件使用的是MASA Blazor,您也可以是其他的UI框架,這個並不影響實際的運行效果,本文案例是相容PC和Android的,演示效果是and ...


是否有小伙伴在使用tab的時候想進行滑動切換Tab?

並且有滑動左出左進,右出右進的效果 ,本文將講解怎麼在Blazor中去通過滑動切換Tab

本文中的UI組件使用的是MASA Blazor,您也可以是其他的UI框架,這個並不影響實際的運行效果,本文案例是相容PC和Android的,演示效果是android中執行的,在PC中執行效果依然有效(親測)

首先安裝MASA Blazor 根據 MASA Blazor安裝MASA Blazor

準備工作

  1. 創建 AppBar.razor文件

  2. 修改MainLayout.razor文件代碼

@inherits LayoutComponentBase

<MApp>
    <AppBar>
        <div class="body">
            @Body
        </div>
    </AppBar>
</MApp>

<style>
.body {
    /*設置內容高度 需要減去導航欄的高度*/
    height: calc(100vh - 48px);
    max-height: calc(100vh - 48px);
}
</style>
  1. 創建 AppBar.razor.css 文件並且添加相關代碼 ,以下代碼是為了實現切換的時候有一個出入效果,具體代碼案例來自Animista - On-Demand CSS Animations Library

    
    /*左邊滑動出*/
    .slide-out-left {
        -webkit-animation: slide-out-left 0.5s;
        animation: slide-out-left 0.5s;
    }
    
    /*右邊滑動出*/
    .slide-out-right {
        -webkit-animation: slide-out-right 0.5s;
        animation: slide-out-right 0.5s;
    }
    
    /*右邊滑動進*/
    .slide-in-right {
        -webkit-animation: slide-in-right 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
        animation: slide-in-right 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
    }
    
    /*左邊滑動進*/
    .slide-in-left {
        -webkit-animation: slide-in-left 0.5s;
        animation: slide-in-left 0.5s;
    }
    
    @-webkit-keyframes slide-out-left {
        0% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    
        100% {
            -webkit-transform: translateX(-1000px);
            transform: translateX(-1000px);
            opacity: 0;
        }
    }
    
    @keyframes slide-out-left {
        0% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    
        100% {
            -webkit-transform: translateX(-1000px);
            transform: translateX(-1000px);
            opacity: 0;
        }
    }
    
    
    @-webkit-keyframes slide-out-right {
        0% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    
        100% {
            -webkit-transform: translateX(1000px);
            transform: translateX(1000px);
            opacity: 0;
        }
    }
    
    @keyframes slide-out-right {
        0% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    
        100% {
            -webkit-transform: translateX(1000px);
            transform: translateX(1000px);
            opacity: 0;
        }
    }
    
    
    @-webkit-keyframes slide-in-left {
        0% {
            -webkit-transform: translateX(-1000px);
            transform: translateX(-1000px);
            opacity: 0;
        }
    
        100% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    }
    
    @keyframes slide-in-left {
        0% {
            -webkit-transform: translateX(-1000px);
            transform: translateX(-1000px);
            opacity: 0;
        }
    
        100% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    }
    @-webkit-keyframes slide-in-right {
        0% {
            -webkit-transform: translateX(1000px);
            transform: translateX(1000px);
            opacity: 0;
        }
    
        100% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    }
    
    @keyframes slide-in-right {
        0% {
            -webkit-transform: translateX(1000px);
            transform: translateX(1000px);
            opacity: 0;
        }
    
        100% {
            -webkit-transform: translateX(0);
            transform: translateX(0);
            opacity: 1;
        }
    }
    
    
  2. 創建AppBar的模型用於動態添加導航欄, 創建AppBarDto.cs文件並添加相關代碼

public class AppBarDto
{
    public string Key { get; set; }

    /// <summary>
    /// 標題
    /// </summary>
    public string Title { get; init; }

    /// <summary>
    /// 圖標
    /// </summary>
    public string? Icon { get; set; }

    /// <summary>
    /// 路由
    /// </summary>
    public string Href { get; init; }

    public AppBarDto(string title, string href, string? icon = null)
    {
        Title = title;
        Icon = icon;
        Href = href;
        Key = Guid.NewGuid().ToString("N");
    }
}
  1. 添加相關頁面,在Pages文件夾下,分別創建Index.razor,Feature.razor,Friend.razor,PersonalCenter.razor

文件相關代碼:
Index.razor

@page "/"
<h3>Index</h3>

Feature.razor

@page "/feature"
<h3>Feature</h3>

Friend.razor

@page "/friend"
<h3>Friend</h3>

PersonalCenter.razor

@page "/personal-center"
<h3>PersonalCenter</h3>
  1. 修改AppBar.razor代碼


<div class="@Class" @ontouchstart="TouchStart" @ontouchend="TouchEnd" @onmousedown="Mousedown" @onmouseup="Mouseup" style="height: 100%">
    @ChildContent
</div>

 @*這裡也可以是其他組件的Tab,其實只是記錄當前的導航的數據*@
<MTabs Centered
       BackgroundColor="indigo"
       ShowArrows="false"
       Value="selectModel.Key"
       Dark>
    @foreach (var i in AppBars)
    {
        <MTab Value="i.Key" OnClick="()=>GoHref(i)">
            @if (!string.IsNullOrEmpty(i.Icon))
            {
                <MIcon Dark>@i.Icon</MIcon>
            }
            @i.Title
        </MTab>
    }
</MTabs>

  1. 創建AppBar.razor.cs 添加以下代碼

public partial class AppBar
{
    #region Inject

    [Inject]
    public required NavigationManager NavigationManager { get; set; }

    #endregion

    private readonly List<AppBarDto> AppBars = new();

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    private AppBarDto selectModel;

    private string Class { get; set; }

    protected override void OnInitialized()
    {
        AppBars.Add(new AppBarDto("首頁", "/", "home"));
        AppBars.Add(new AppBarDto("好友", "/personal-center", "mdi-account-group-outline"));
        AppBars.Add(new AppBarDto("功能", "/feature", "mdi-wrench"));
        AppBars.Add(new AppBarDto("個人中心", "/personal-center", "mdi-badge-account-alert"));

        // 預設選擇的導航標簽
        selectModel = AppBars[0];

        base.OnInitialized();
    }

    /// <summary>
    /// 導航欄跳轉
    /// </summary>
    /// <param name="appBar"></param>
    private void GoHref(AppBarDto appBar)
    {
        // 防止重覆點擊
        if(appBar == selectModel)
        {
            return;
        }

        // 當點擊導航的索引大於現在導航時啟動滑動效果
        if(AppBars.IndexOf(appBar) > AppBars.IndexOf(selectModel))
        {
            Class = "slide-out-left";
            Task.Run(async () =>
            {
                // 由於特效時間為0.5s 這裡是等待特效完成
                await Task.Delay(450);
                NavigationManager.NavigateTo(selectModel.Href);
                Class = "slide-in-right";
                _ = InvokeAsync(StateHasChanged);
            });
        }
        // 當點擊導航的索引小於現在導航時啟動滑動效果
        else if (AppBars.IndexOf(appBar) < AppBars.IndexOf(selectModel))
        {
            Class = "slide-out-right";
            Task.Run(async () =>
            {
                // 由於特效時間為0.5s 這裡是等待特效完成
                await Task.Delay(450);
                NavigationManager.NavigateTo(selectModel.Href);
                Class = "slide-in-left";
                _ = InvokeAsync(StateHasChanged);
            });
        }
        selectModel = appBar;
        NavigationManager.NavigateTo(appBar.Href);
    }


    /// <summary>
    /// 開始X坐標
    /// </summary>
    private double _startX;


    #region 移動端滑動處理

    /// <summary>
    /// 記錄開始坐標
    /// </summary>
    /// <param name="args"></param>
    private void TouchStart(TouchEventArgs args)
    {
        var touch = args.ChangedTouches[0];
        _startX = touch.ScreenX;
    }

    private void TouchEnd(TouchEventArgs args)
    {
        var touch = args.ChangedTouches[0];
        Switchover((decimal)touch.ScreenX);
    }

    #endregion

    #region PC滑動處理

    /// <summary>
    /// 記錄開始坐標
    /// </summary>
    /// <param name="args"></param>
    private void Mousedown(MouseEventArgs args)
    {
        _startX = args.ScreenX;
    }

    private void Mouseup(MouseEventArgs args)
    {
        Switchover((decimal)args.ScreenX);
    }

    #endregion

    private void Switchover(decimal screenX)
    {
        var index = AppBars.IndexOf(selectModel);
        // 限制過度滑動
        if (index == AppBars.Count || index > AppBars.Count)
        {
            return;
        }

        // 設置滑動最大位限制,達到這個限制才滑動生效
        var size = 200;

        // 需要滑動200才切換 如果開始坐標x大於 當前結束的x坐標往右邊切換tab
        if ((decimal)_startX - size > screenX)
        {
            // 如果右邊往左邊滑動 當前索引是當前最大數量的話不需要切換
            if (index == AppBars.Count - 1)
            {
                return;
            }
            selectModel = AppBars[index + 1];
            Class = "slide-out-left";

            Task.Run(async () =>
            {
                // 由於特效時間為0.5s 這裡是等待特效完成
                await Task.Delay(450);
                NavigationManager.NavigateTo(selectModel.Href);
                Class = "slide-in-right";
                _ = InvokeAsync(StateHasChanged);
            });
        }
        else if ((decimal)_startX + size < screenX)
        {
            // 如果左邊往右邊滑動 當前索引是0的話不需要切換
            if (index == 0)
            {
                return;
            }
            selectModel = AppBars[index - 1];
            Class = "slide-out-right";
            Task.Run(async () =>
            {
                // 由於特效時間為0.5s 這裡是等待特效完成
                await Task.Delay(450);
                NavigationManager.NavigateTo(selectModel.Href);
                Class = "slide-in-left";
                _ = InvokeAsync(StateHasChanged);
            });
        }
    }
}

運行效果:

一個熱愛學習的token

qq交流群:737776595
微信交流群:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 兔年到了,祝大家身體健,康萬事順利。本文內容作為兔年新春紀念頁面,將使用 Three.js 及 其他前端開發知識,創建一個以兔子為主題的 3D 簡單的趣味頁面 Rabbit craft go。本文內容包括使用純代碼創建三維浮島、小河、樹木、兔子、胡蘿蔔以及兔子的運動交互、浮島的動畫效果等。本文包含的... ...
  • JavaScript 中的記憶體管理主要由 JavaScript 引擎負責,開發人員不需要手動管理記憶體。JavaScript 引擎使用垃圾回收演算法來實現自動垃圾回收。 JavaScript 垃圾回收演算法是指在 JavaScript 程式中,用來回收不再使用的記憶體的演算法。 ...
  • 使用 CSS 的 box-sizing 屬性 MDN docs 關於box-sizing 一種解決方法是使用 CSS 的 box-sizing 屬性來控制元素的盒模型。預設情況下,盒模型是 "content-box",這意味著元素的寬度和高度只包括其內容,而不包括 padding 和 border。 ...
  • 最近寫了個 python 的 tkinter 框架入門教程,希望給大家介紹一下這個框架的上手過程,這是一個系列文章,現在是第一篇。 ...
  • 2023-01-22 一、SSM整合 1、Spring + SpringMVC (1)容器管理對象,由DispatcherServlet管理 (2)Spring容器對象,由ContextLoaderListener管理 2、解決組件掃描的衝突問題 (1)SpringMVC只掃描Controller層 ...
  • 這篇筆記咱日後應該還會進行補充。 關於sort的比較函數 STL的algorithm庫中的sort函數,可以接受一個cmp函數作為第三個參數,用來指定排序的規則。 自定義sort比較函數 cmp(a,b)函數的返回值是一個bool值,當返回值為true時不改變元素順序。 可以把其中的a看作序列中前一 ...
  • 2023-01-22 一、SpringMVC攔截器的兩種裝配方式 1、全局裝配(放置在springmvc.xml中) <!-- 裝配攔截器--> <!-- 全局裝配--> <mvc:interceptors> <ref bean="myInterceptor"></ref> </mvc:interc ...
  • 題目描述 牛牛從鍵盤上輸入三個整數,並嘗試在屏幕上顯示第二個整數。 輸入描述 一行輸入 3 個整數,用空格隔開。 輸出描述 請輸出第二個整數的值。 示例 1 輸入:1 2 3 輸出:2 解題思路 方案一 使用 3 個整形變數依次存儲輸入的 3 個整數,然後將第二個整形變數的數據輸出。 具體代碼如下: ...
一周排行
    -Advertisement-
    Play Games
  • MQTTnet 是一個高性能的MQTT類庫,支持.NET Core和.NET Framework。 MQTTnet 原理: MQTTnet 是一個用於.NET的高性能MQTT類庫,實現了MQTT協議的各個層級,包括連接、會話、發佈/訂閱、QoS(服務質量)等。其原理涉及以下關鍵概念: MqttCli ...
  • 在WPF中,源屬性(Source Property)指的是提供數據的屬性,通常是數據模型或者其他控制項的屬性,而目標屬性(Target Property)則是數據綁定的目標,通常是綁定到控制項的屬性,例如TextBlock的Text屬性。數據綁定將源屬性的值自動更新到目標屬性中。 主要包含以下幾個事件: ...
  • async/await 是 C# 中非同步編程的關鍵特性,它使得非同步代碼編寫更為簡單和直觀。下麵深入詳細描述了 async/await 的使用場景、優點以及一些高級使用方法,並提供了相應的實例源代碼。 使用場景: I/O 操作: 非同步編程特別適用於涉及 I/O 操作(如文件讀寫、網路請求等)的場景。在 ...
  • 使用過office的visio軟體畫圖的小伙伴都知道,畫圖軟體分為兩部分,左側圖形庫,存放各種圖標,右側是一個畫布,將左側圖形庫的圖標控制項拖拽到右側畫布,就會生成一個新的控制項,並且可以自由拖動。那如何在WPF程式中,實現類似的功能呢?今天就以一個簡單的小例子,簡述如何在WPF中實現控制項的拖拽和拖動,... ...
  • 1、Blazor Hybrid簡介 Blazor Hybrid 使開發人員能夠將桌面和移動本機客戶端框架與 .NET 和 Blazor 結合使用。在 Blazor Hybrid 應用中,Razor 組件在設備上是本機運行的。 這些組件通過本地互操作通道呈現到嵌入式 Web 視圖控制項。 組件不在瀏覽器 ...
  • 除了內置的數據集,scikit-learn還提供了隨機樣本的生成器。通過這些生成器函數,可以生成具有特定特性和分佈的隨機數據集,以幫助進行機器學習演算法的研究、測試和比較。 目前,scikit-learn庫(v1.3.0版)中有20個不同的生成樣本的函數。本篇重點介紹其中幾個具有代表性的函數。 1. ...
  • 從0到1,手把手帶你開發截圖工具ScreenCap------002實現通過文件對話框,選擇合適的文件夾,自定義預設的圖片保存位置,簡單易學 ...
  • 每次談到容器的時候,除了Docker之外,都會說起 Kubernetes,那麼什麼是 Kubernetes呢?今天就來一起學快速入門一下 Kubernetes 吧!希望本文對您有所幫助。 Kubernetes,一種用於管理和自動化雲中容器化工作負載的工具。 想象一下你有一個管弦樂隊,將每個音樂家視為 ...
  • 目錄 基本說明 安裝 Nginx 部署 VUE 前端 部署 Django 後端 Django admin 靜態文件(CSS,JS等)丟失的問題 總結 1. 基本說明 本文介紹了在 windows 伺服器下,通過 Nginx 部署 VUE + Django 前後端分離項目。本項目前端運行在 80 埠 ...
  • 從0到1,手把手帶你開發截圖工具ScreenCap------003實現最小化程式到托盤運行,- 為了方便截圖乾凈,實現最小化程式到托盤運行,簡潔,勿擾,實現最小化程式到托盤運行, 實現托盤菜單功能,實現回顯主窗體, 實現托盤開始截屏, 實現氣泡信息提示,實現托盤程式提示,實現托盤退出程式, 封裝完... ...