代码之家  ›  专栏  ›  技术社区  ›  Vencovsky

访问导航管理器是否返回?

  •  0
  • Vencovsky  · 技术社区  · 4 年前

    在使用blazor时,我希望能够“回到”以前的页面。

    我找到了这个 issue 看起来这是一条死胡同?

    这个功能太基本了,我不敢相信它不存在。

    是否有任何方法可以实现这种“返回”功能?

    请注意,我无法使用 window.goBack history.goBack 因为我的应用程序不会创建任何历史,也不应该创建任何历史。

    “创建”历史的唯一方法是使用 forceLoad 选项 Navigation.NavigateTo 但如果我这样做,它会尝试再次加载我的整个应用程序,这很慢,我不想加载。

    0 回复  |  直到 4 年前
        1
  •  21
  •   cabiste    2 年前

    您需要的是页面历史状态管理器:

    对于以下示例,我使用的是DateTimeWasm,但您也可以在DateTimeServer中使用此示例。

    在客户端应用程序中,我添加了此类: 页面历史状态:

     public class PageHistoryState
        {
            private List<string> previousPages;
    
            public PageHistoryState()
            {
                previousPages = new List<string>();
            }
            public void AddPageToHistory(string pageName)
            {
                previousPages.Add(pageName);
            }
    
            public string GetGoBackPage()
            {
                if (previousPages.Count > 1)
                {
                    // You add a page on initialization, so you need to return the 2nd from the last
                    return previousPages.ElementAt(previousPages.Count - 2);
                }
    
                // Can't go back because you didn't navigate enough
                return previousPages.FirstOrDefault();
            }
    
            public bool CanGoBack()
            {
                return previousPages.Count > 1;
            }
        }
    

    然后将此类作为单例添加到服务中:

    builder.Services.AddSingleton<PageHistoryState>();
    

    将其注入您的页面:

    @inject WasmBlazor.Client.PageHistoryState PageHistoryState
    

    在我的标记中,我检查是否可以返回页面:

    @if (PageHistoryState.CanGoBack())
    {
        <a href="@PageHistoryState.GetGoBackPage()">Go Back</a>
    }
    

    我已经覆盖了 OnInitialized()

    protected override void OnInitialized()
    {
        PageHistoryState.AddPageToHistory("/counter");
        base.OnInitialized();
    }
    

    我在“获取数据”页面中做了同样的事情,我可以在不需要JSInterop的情况下返回。

        2
  •  15
  •   SeriousM Boris Ivanov    2 年前

    我最终提出了一个稍微改进的解决方案,它封装了NavigationManager,将所有内容保存在一个地方,不依赖于Pages或其他东西。它还将历史缓冲区大小保持在合理的范围内。

    导航cs

    using System;
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Routing;
    
    namespace MyApp
    {
        public class Navigation : IDisposable
        {
            private const int MinHistorySize = 256;
            private const int AdditionalHistorySize = 64;
            private readonly NavigationManager _navigationManager;
            private readonly List<string> _history;
    
            public Navigation(NavigationManager navigationManager)
            {
                _navigationManager = navigationManager;
                _history = new List<string>(MinHistorySize + AdditionalHistorySize);
                _history.Add(_navigationManager.Uri);
                _navigationManager.LocationChanged += OnLocationChanged;
            }
    
            /// <summary>
            /// Navigates to the specified url.
            /// </summary>
            /// <param name="url">The destination url (relative or absolute).</param>
            public void NavigateTo(string url)
            {
                _navigationManager.NavigateTo(url);
            }
    
            /// <summary>
            /// Returns true if it is possible to navigate to the previous url.
            /// </summary>
            public bool CanNavigateBack => _history.Count >= 2;
    
            /// <summary>
            /// Navigates to the previous url if possible or does nothing if it is not.
            /// </summary>
            public void NavigateBack()
            {
                if (!CanNavigateBack) return;
                var backPageUrl = _history[^2];
                _history.RemoveRange(_history.Count - 2, 2);
                _navigationManager.NavigateTo(backPageUrl);
            }
    
            // .. All other navigation methods.
    
            private void OnLocationChanged(object sender, LocationChangedEventArgs e)
            {
                EnsureSize();
                _history.Add(e.Location);
            }
    
            private void EnsureSize()
            {
                if (_history.Count < MinHistorySize + AdditionalHistorySize) return;
                _history.RemoveRange(0, _history.Count - MinHistorySize);
            }
    
            public void Dispose()
            {
                _navigationManager.LocationChanged -= OnLocationChanged;
            }
        }
    }
    

    然后,您可以将此类作为单例服务添加到依赖注入中并初始化。

    程序cs

    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace MyApp
    {
        public class Program
        {
            public static async Task Main(string[] args)
            {
                var builder = WebAssemblyHostBuilder.CreateDefault(args);
                builder.RootComponents.Add<App>("app");
    
                builder.Services.AddSingleton<Navigation>();
                // .. other services.
                
                var host = builder.Build();
                await Initialize(host);
                await host.RunAsync();
            }
    
            private static async Task Initialize(WebAssemblyHost host)
            {
                host.Services.GetService<Navigation>();
                // .. other initialization calls.
            }
        }
    }
    

    之后,您可以使用Inject指令/属性在任何地方使用它。

    SomePage.cshtml

    @page "/SomePage"
    @inject Navigation Navigation
    
    <h3>SomePage</h3>
    
    <button @onclick="NavigateBackClick">Navigate Back</button>
    
    @code {
        private void NavigateBackClick()
        {
            Navigation.NavigateBack();
        }
    }
    

    SomeService.cs

    namespace MyApp
    {
        public class SomeService
        {
            private readonly Navigation _navigation;
    
            public SomeService(Navigation navigation)
            {
                _navigation = navigation;
            }
    
            public void SomeMethod()
            {
                // ...
                _navigation.NavigateBack();
            }
        }
    }
    
        3
  •  15
  •   Ramil Aliyev 007    1 年前

    使用Javascript怎么样?

    @inject IJSRuntime JSRuntime
    
    // Go back in browser using Javascript on a Razor Page 
    private async Task GoBack()
    {
        await JSRuntime.InvokeVoidAsync("history.back");
    }
    
        4
  •  10
  •   mfluehr fermar    2 年前

    我修改了迪奥戈上面的答案,我觉得这是一个更优雅的解决方案。

    首先,创建一个 BasePageComponent.cs 类,它继承自 ComponentBase 类别:

    // Using statements/namespace go here
    
    [Authorize]
    public class BasePageComponent: ComponentBase
    {
        [Inject]
        protected NavigationManager _navManager { get; set; }
        [Inject]
        protected PageHistoryState _pageState { get; set; }
    
        public BasePageComponent(NavigationManager navManager, PageHistoryState pageState)
        {
            _navManager = navManager;
            _pageState = pageState;
        }
    
        public BasePageComponent()
        {
        }
    
        protected override void OnInitialized()
        {
            base.OnInitialized();
            _pageState.AddPage(_navManager.Uri);
        }
    }
    

    这是您的每个页面将继承的内容。它处理注射 PageHistoryState 服务,以及附加一个新导航的页面。它在你实际页面的“幕后”完成了这一切。

    现在,在给定的页面中,您继承自 BasePageComponent :

    @page "/workouts/new"
    @inherits BasePageComponent
    
    /* ...RenderFragments/Razor view here...*/
    
    @code {
        /* ...properties here...*/
    
        // This is an example of how to consume the _navManager and _pageState objects if desired, without any boilerplate code.
        private void OnCancel()
        {
            _navManager.NavigateTo(_pageState.PreviousPage());
        }
    }
    

    在我的示例组件中(为简洁起见而去掉),它向页面历史堆栈中添加了一个新元素,除了继承自 基础页面组件 . 泰勒

        5
  •  0
  •   mfluehr fermar    2 年前

    这是一个扩展 Diogo's answer .

    正确执行 PageHistoryState 应该使用Stack。记住,你必须为历史添加一些起点。你应该打个电话 AddPageToHistory 在您的第一个页面加载时(可能是MainLayout)。如果历史记录为空,您将被重定向到错误页面:

    public class PageHistoryState
    {
        private Stack<string> previousPages;
        private Stack<string> nextPages;
        private readonly string errorPageUrl;
        public PageHistoryState()
        {
            previousPages = new Stack<string>();
            nextPages = new Stack<string>();
            errorPageUrl = "/errorPage";
        }
    
        public void AddPageToHistory(string pageName)
        {
            previousPages.Push(pageName);
        }
    
        public string GetGoBackPage()
        {
            // This condition is to check if it is the first loaded page "/"
            if (previousPages.TryPeek(out string url) && !string.IsNullOrWhiteSpace(url))
            {
                // If moved to the next page check
                if (previousPages.Count > 1)
                {
                    // Pop the current page
                    nextPages.Push(previousPages.Pop());
                    // Pop the previous page -> "/"
                    url = previousPages.Pop();
                    return url;
                }
            }
    
            // If stack is empty redirect to the error page
            return errorPageUrl;
        }
    
        public string GetGoForwardPage()
        {
            if (nextPages.TryPop(out string url) && !string.IsNullOrWhiteSpace(url))
                return url;
    
            // If stack is empty redirect to the error page
            return errorPageUrl;
        }
    
        public bool CanGoForward() => nextPages.Any();
        public bool CanGoBack() => previousPages.Count > 1;
    }
    
        6
  •  0
  •   SeriousM Boris Ivanov    2 年前

    导航类

     public class Navigator
        {
            string _currentPage = "/";
            string _homePage { get; set; } = "/";
            NavigationManager Navigation { get; set; }
            IJSRuntime JS { get; set; }
            public void SetNavigation(NavigationManager navigation, IJSRuntime js, string dfaultPage = "/")
            {
                this.Navigation = navigation;
                this.JS = js;
                _currentPage = dfaultPage;
                _homePage = _currentPage;
            }
            public Navigator()
            {
                
            }
            public Stack<string> Navigators = new Stack<string>();
            public void NavigateTo(string parameter)
            {
                if (parameter != _currentPage)
                {
                    Navigators.Push(parameter);
                    Navigation?.NavigateTo(parameter);
                    _currentPage = parameter;
                }
            }
            public async void ExecuteCommand(NavigateType code, string param)
            {
                if (code ==  NavigateType.Back)
                {
                    if (Navigators.Count >= 1)
                    {
                        string nav = null;
                        if(Peek() == param)
                            Navigators.Pop();
                        if(Navigators.Count >=1)
                          nav = Navigators.Pop();
                        if (nav != null)
                            _currentPage = nav;
                        else
                        {
                            _currentPage = _homePage;
                        }
                        await JS.InvokeVoidAsync("history.back");
                        BackPressed?.Invoke(this, nav);
                    }
                    else
                    {
                       
                        _currentPage = _homePage;
                        await JS.InvokeVoidAsync("history.back");
                        BackPressed?.Invoke(this, null);
                       
                    }
                    
                }
                else if (code == NavigateType.Navigate)
                {
                    if (param != _currentPage)
                    {
                        _currentPage = param;
                        Navigators.Push(param);
                        Navigation?.NavigateTo(param);
                        Navigated?.Invoke(this, param);
                    }
    
                }
            }
            public string Peek()
            {
                return Navigators.Peek();
            }
            public string Pop()
            {
                return Navigators.Pop();
            }
            public event EventHandler<string> BackPressed;
            public event EventHandler<string> Navigated;
        }
        public enum NavigateType
        {
            Navigate,
            Back,
    
        }
    
        7
  •  0
  •   user1489673 user1489673    2 年前

    我创建了自己的类,并将其注册为服务。我没有使用客户端注册页面更改,而是使用了MainLayout,因此不需要JS。

    我将服务注入到需要后退按钮的页面中

    我还将其添加到MainLayout中

    <a href="@pvs.GetPreviousPage()">Go Back</a>
    
    
    
    
    
    
     @code {
        protected override void OnInitialized()
        {
            pvs.AddPage(NavigationManager.Uri);
    
            NavigationManager.LocationChanged += LocationChanged;
            base.OnInitialized();
        }
    
        void LocationChanged(object? sender, LocationChangedEventArgs e)
        {
            if (sender is NavigationManager vm)
            {
                pvs.AddPage(NavigationManager.Uri);
            }
        }
    }
    

    公共类页面访问服务 { 列表_页面访问历史=新列表();

        /// <summary>
        /// Gets a cloned list of history
        /// </summary>
        public List<string> PageVisitHistory
        {
            get
            {
                return new List<string>(_pageVisitHistory.Reverse<string>());
            }
        }
    
    
        public void AddPage(string page)
        {
            if (_pageVisitHistory.Count > 0 && page == _pageVisitHistory[_pageVisitHistory.Count - 1])
            {
                return;
            }
    
            _pageVisitHistory.Add(page);
        }
    
        public string GetPreviousPage()
        {
            if (_pageVisitHistory.Count > 0)
            {
                return _pageVisitHistory[_pageVisitHistory.Count - 1];
            }
    
            return string.Empty;
        }
    }
    
    推荐文章