Does anyone want to swipe to switch tabs when using tabs?
And there is the effect of sliding left out, left in, right out of right in, this article will explain how Blazor
to switch Tab by sliding in the middle
The UI components in this article are used MASA Blazor
, you can also use other UI frameworks, this does not affect the actual running effect, the case in this article is compatible with PC and Android, the demonstration effect is executed in android, and the execution effect in PC is still the same Effective (pro-test)
Install first Install MASA Blazor
according to MASA BlazorMASA Blazor
Preparation
-
create
AppBar.razor
file -
modify
MainLayout.razor
file code
@inherits LayoutComponentBase
<MApp>
<AppBar>
<div class="body">
@Body
</div>
</AppBar>
</MApp>
<style>
.body {
/*设置内容高度 需要减去导航栏的高度*/
height: calc(100vh - 48px);
max-height: calc(100vh - 48px);
}
</style>
-
Create
AppBar.razor.css
a file and add relevant codes. The following codes are used to achieve an in-and-out effect when switching. The specific code examples are from 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; } }
-
The created
AppBar
model is used to dynamically add the navigation bar, createAppBarDto.cs
files and add related codes
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");
}
}
- Add related pages,
Pages
under the folder, respectively createIndex.razor
,Feature.razor
,Friend.razor
,PersonalCenter.razor
File related code:
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>
- modify
AppBar.razor
the code
<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>
- Create
AppBar.razor.cs
add the following code
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);
});
}
}
}
running result:
A token that loves to learn
Qq exchange group: 737776595
WeChat exchange group: