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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...