From 2528e45410605ab17ff5218989ec3188ec0851ef Mon Sep 17 00:00:00 2001 From: capdiem Date: Wed, 6 Nov 2024 15:46:10 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=95=20feat(PageStack):=20add=20support?= =?UTF-8?q?=20for=20current=20active=20tab=20change=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Shared/PageStackLayout.razor | 7 +++- .../NavController/PageStackNavController.cs | 16 ++++++-- .../PageStackTabChangedEventArgs.cs | 17 ++++++++ .../Presets/PageStack/PPageStack.razor.cs | 40 +++++++++++++++---- 4 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 src/Masa.Blazor/Presets/PageStack/NavController/PageStackTabChangedEventArgs.cs diff --git a/docs/Masa.Blazor.Docs/Shared/PageStackLayout.razor b/docs/Masa.Blazor.Docs/Shared/PageStackLayout.razor index 1020e2567f..aa5622ea69 100644 --- a/docs/Masa.Blazor.Docs/Shared/PageStackLayout.razor +++ b/docs/Masa.Blazor.Docs/Shared/PageStackLayout.razor @@ -19,6 +19,11 @@ @code { - private string[] _tabbedPatterns = ["/blazor/examples/page-stack/tab*"]; + private string[] _tabbedPatterns = + [ + "/blazor/examples/page-stack/tab1", + "/blazor/examples/page-stack/tab2", + "/blazor/examples/page-stack/tab3" + ]; } \ No newline at end of file diff --git a/src/Masa.Blazor/Presets/PageStack/NavController/PageStackNavController.cs b/src/Masa.Blazor/Presets/PageStack/NavController/PageStackNavController.cs index 864c65f1b4..e10999d18e 100644 --- a/src/Masa.Blazor/Presets/PageStack/NavController/PageStackNavController.cs +++ b/src/Masa.Blazor/Presets/PageStack/NavController/PageStackNavController.cs @@ -20,7 +20,7 @@ public class PageStackNavController() public event EventHandler? StackPop; /// - /// Occurs when a page is replaced by a new page. + /// Occurs when a new page replaces a page. /// public event EventHandler? StackReplace; @@ -39,6 +39,11 @@ public class PageStackNavController() /// internal event EventHandler? StackGoBackTo; + /// + /// Occurs when the active tab is changed. + /// + public event EventHandler? TabChanged; + /// /// Push a new page onto the page stack. /// @@ -126,7 +131,7 @@ public void Clear() } /// - /// Clear current page stack and navigate to a tab. + /// Clear the current page stack and navigate to a tab. /// /// [Obsolete("Use GoBackToTab instead.")] @@ -136,7 +141,7 @@ public void GoToTab(string relativeUri) } /// - /// Clear current page stack and navigate to a tab. + /// Clear the current page stack and navigate to a tab. /// /// public void GoBackToTab(string relativeUri) @@ -149,6 +154,11 @@ internal void NotifyPageClosed(string relativeUri) PageClosed?.Invoke(this, new PageStackPageClosedEventArgs(relativeUri)); } + internal void NotifyTabChanged(string currentTabPath, Regex currentTabPattern) + { + TabChanged?.Invoke(this, new PageStackTabChangedEventArgs(currentTabPath, currentTabPattern.IsMatch)); + } + private void ExecuteIfTimeElapsed(Action action) { var now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); diff --git a/src/Masa.Blazor/Presets/PageStack/NavController/PageStackTabChangedEventArgs.cs b/src/Masa.Blazor/Presets/PageStack/NavController/PageStackTabChangedEventArgs.cs new file mode 100644 index 0000000000..184bdf0ee2 --- /dev/null +++ b/src/Masa.Blazor/Presets/PageStack/NavController/PageStackTabChangedEventArgs.cs @@ -0,0 +1,17 @@ +namespace Masa.Blazor.Presets.PageStack.NavController; + +public class PageStackTabChangedEventArgs(string currentTab, Func isMatch) : EventArgs +{ + /// + /// The absolute path of the current tab. + /// + public string CurrentTab { get; init; } = currentTab; + + /// + /// Checks whether the given path matches the current tab. + /// + /// + /// True if the path matches the current tab; otherwise, false. + /// + public Func IsMatch { get; init; } = isMatch; +} \ No newline at end of file diff --git a/src/Masa.Blazor/Presets/PageStack/PPageStack.razor.cs b/src/Masa.Blazor/Presets/PageStack/PPageStack.razor.cs index be3f6b07f2..ca95542106 100644 --- a/src/Masa.Blazor/Presets/PageStack/PPageStack.razor.cs +++ b/src/Masa.Blazor/Presets/PageStack/PPageStack.razor.cs @@ -1,5 +1,6 @@ using Masa.Blazor.Presets.PageStack; using Masa.Blazor.Presets.PageStack.NavController; +using Microsoft.AspNetCore.Components.Routing; namespace Masa.Blazor.Presets; @@ -25,16 +26,18 @@ public partial class PPageStack : PatternPathComponentBase internal readonly StackPages Pages = new(); /// - /// Determines whether the popstate event is triggered by user action, + /// Determines whether user action triggers the popstate event, /// different from the browser's back button. /// private bool _popstateByUserAction; private string? _lastVisitedTabPath; private PageType _targetPageType; - private string? _latestTabPath; private long _lastOnPreviousClickTimestamp; + // just for knowing whether the tab has been changed + private (Regex Pattern, string AbsolutePath) _lastVisitedTab; + private HashSet _prevTabbedPatterns = new(); private HashSet _cachedTabbedPatterns = new(); @@ -54,6 +57,8 @@ protected override void OnInitialized() { _lastVisitedTabPath = targetPath; _targetPageType = PageType.Tab; + + _lastVisitedTab = (tabbedPattern, targetPath); } else { @@ -61,6 +66,8 @@ protected override void OnInitialized() Push(NavigationManager.Uri); } + NavigationManager.LocationChanged += NavigationManagerOnLocationChanged; + InternalPageStackNavManager = PageStackNavControllerFactory.Create(Name ?? string.Empty); InternalPageStackNavManager.StackPush += InternalStackStackNavManagerOnStackPush; InternalPageStackNavManager.StackPop += InternalPageStackNavManagerOnStackPop; @@ -71,6 +78,20 @@ protected override void OnInitialized() _dotNetObjectReference = DotNetObjectReference.Create(this); } + private void NavigationManagerOnLocationChanged(object? sender, LocationChangedEventArgs e) + { + var currentPath = NavigationManager.GetAbsolutePath(); + var tabbedPattern = _cachedTabbedPatterns.FirstOrDefault(u => u.IsMatch(currentPath)); + + if (tabbedPattern is not null && _lastVisitedTab.Pattern != tabbedPattern) + { + Console.Out.WriteLine($"Tab {_lastVisitedTab.AbsolutePath} to Tab {currentPath}"); + _lastVisitedTab = (tabbedPattern, currentPath); + + InternalPageStackNavManager?.NotifyTabChanged(currentPath, tabbedPattern); + } + } + protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); @@ -171,7 +192,8 @@ private async void InternalStackStackNavManagerOnStackClear(object? sender, Page { await Js.InvokeVoidAsync(JsInteropConstants.HistoryGo, -Pages.Count); - var backToLastVisitTab = string.IsNullOrWhiteSpace(e.RelativeUri) || _lastVisitedTabPath == GetAbsolutePath(e.RelativeUri); + var backToLastVisitTab = string.IsNullOrWhiteSpace(e.RelativeUri) || + _lastVisitedTabPath == GetAbsolutePath(e.RelativeUri); if (backToLastVisitTab) { @@ -278,11 +300,7 @@ private void DisableRootScrollbar(bool disable) protected override async ValueTask DisposeAsyncCore() { - if (_module is not null) - { - await _module.InvokeVoidAsync("detachListener", _dotnetObjectId); - await _module.DisposeAsync(); - } + NavigationManager.LocationChanged -= NavigationManagerOnLocationChanged; if (InternalPageStackNavManager is not null) { @@ -292,6 +310,12 @@ protected override async ValueTask DisposeAsyncCore() InternalPageStackNavManager.StackClear -= InternalStackStackNavManagerOnStackClear; InternalPageStackNavManager.StackGoBackTo -= InternalPageStackNavManagerOnStackGoBackTo; } + + if (_module is not null) + { + await _module.InvokeVoidAsync("detachListener", _dotnetObjectId); + await _module.DisposeAsync(); + } } private enum PageType