欢迎访问www.allbetgaming.com!

首页科技正文

日照置业网:[Asp.Net Core] Blazor Server Side 项目实践 - 切换页面时保留状态

admin2020-04-265

前言:

这是 项目实践系列 , 算是中高级系列博文, 用于为项目开发历程中欠好解决的问题提出解决方案的. 不属于入门级系列. 注释起来也对照跳跃, 只讲重点.

由于有网友的项目需求, 以是提前把这些解决方案做出来并分享.

 

问题:

Blazor自己是携带一个简朴的路由功效的, 当切换Url的时刻, 整个通过把RouteData传递给 App.razor 加载 MainLayout , 实现页面刷新的目的.

若是跳转到另外一个页面, 然后再跳回来的时刻, 希望原来页面不刷新, 保留之前的状态 , 例如搜索条件, 那么怎么办?

 

解决历程:

连系视频, 图文旁观效果最好 : https://www.bilibili.com/video/BV1g54y1R7uX/ 

1. 现在简朴说说, 这种情形的源头在那里.
2. App.razor 文件使用了 RouteView 来实现路由
3. routeData是包罗页面类型, 以及页面参数的.
4. 然而默认的实现里, RouteView 是不带状态的
5. MainLayout虽然获得了内容的 RenderFragment ,
6. 然而这个 RenderFragment是由RouteView直接绑定到routeData上面去.
7. 以是MainLayout无法获得差别的RenderFragment来显示差别的内容.
8. 要解决这个问题, 首先第一步就是革新 RouteView

革新 RouteView

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components.Rendering;
using System.Reflection;

namespace Microsoft.AspNetCore.Components   //use this namepace so copy/paste this code easier
{

    public class KeepPageStateRouteView : RouteView
    {
        protected override void Render(RenderTreeBuilder builder)
        {
            var layoutType = RouteData.PageType.GetCustomAttribute<LayoutAttribute>()?.LayoutType ?? DefaultLayout;
            builder.OpenComponent<LayoutView>(0);
            builder.AddAttribute(1, "Layout", layoutType);
            builder.AddAttribute(2, "ChildContent", (RenderFragment)CreateBody());
            builder.CloseComponent();
        }

        RenderFragment CreateBody()
        {
            var pagetype = RouteData.PageType;
            var routeValues = RouteData.RouteValues;

            void RenderForLastValue(RenderTreeBuilder builder)
            {
                //dont reference RouteData again

                builder.OpenComponent(0, pagetype);
                foreach (KeyValuePair<string, object> routeValue in routeValues)
                {
                    builder.AddAttribute(1, routeValue.Key, routeValue.Value);
                }
                builder.CloseComponent();
            }

            return RenderForLastValue;
        }

    }

}

 

Blazor自带的RouteView是一个控件. 它每次出现, 都使用 RouteData 属性, 以是它每次天生的 RenderFragment 都是随着最后的 RouteData 走, 保留来没用.

革新后的 KeepPageStateRouteView , 使用 CreateBody() 方式, 创建出绑定 pagetype 和 routevalue 的 RenderFragement , 为 MainLayout 打下基础

 

革新 MainLayout 

@inherits LayoutComponentBase

@inject NavigationManager navmgr

@code{

    TimeSpan GetUrlMaxLifeSpan(string url)
    {
        if (url.Contains("/fetchdata")) // Let /fetachdata always refresh
            return TimeSpan.Zero;

        if (url.Contains("/counter"))   // Let /counter expires in 10 seconds
            return TimeSpan.FromSeconds(10);

        return TimeSpan.FromSeconds(-1);    //other pages never expires
    }

    class PageItem
    {
        public string Url;
        public RenderFragment PageBody;
        public DateTime StartTime = DateTime.Now;
        public DateTime ActiveTime = DateTime.Now;
        public TimeSpan MaxLifeSpan;
    }

    Dictionary<string, PageItem> bodymap = new Dictionary<string, PageItem>();

    int mainRenderCount = 0;
}

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">


    @{

        bool currurlrendered = false;

        string currenturl = navmgr.Uri;

        PageItem curritem;
        if (bodymap.TryGetValue(currenturl, out curritem))
        {
            curritem.ActiveTime = DateTime.Now;
        }
        else
        {
            curritem = new PageItem { Url = currenturl, PageBody = Body };
            curritem.MaxLifeSpan = GetUrlMaxLifeSpan(currenturl);
            if (curritem.MaxLifeSpan != TimeSpan.Zero)
            {
                bodymap[navmgr.Uri] = curritem;
            }
        }

        mainRenderCount++;

    }

    <div class="top-row px-4">


        #@mainRenderCount

        , CurrentUrl : @currenturl

        . PageCount : @bodymap.Count
        ,
        <button @onclick="StateHasChanged">StateHasChanged</button>

    </div>


    @foreach (PageItem eachitem in bodymap.Values.ToArray())
    {

        string pageurl = eachitem.Url;
        RenderFragment pagebody = eachitem.PageBody;

        string divstyle = "display:none";
        if (pageurl == currenturl)
        {
            divstyle = "";
            currurlrendered = true;
        }
        else if (eachitem.MaxLifeSpan.TotalSeconds > 0 && DateTime.Now - eachitem.ActiveTime > eachitem.MaxLifeSpan)
        {
            bodymap.Remove(eachitem.Url);
            continue;
        }

        <div @key="pageurl" class="content px-4" style="@divstyle">
            @pagebody
        </div>
    }

    @if (!currurlrendered)
    {
        <div class="content px-4">
            @Body
        </div>
    }

</div>

 


MainLayout 里, 最要害的是 Dictionary<string, PageItem> bodymap = new Dictionary<string, PageItem>();

这个字典, Key 是 Url , 而 PageItem 则储存了这个 Url 的多个信息.

类型使用了 TimeSpan GetUrlMaxLifeSpan(string url) 函数来制订页面的生计时间规则.

若是页面的生计时间是 0 , 示意不加进 bodymap , 每次都要所有刷新.

生计时间不为0 , 就储存到 bodymap 内里去. 然后在

@foreach (PageItem eachitem in bodymap.Values.ToArray())

循环历程中, 把每一个页面 Render 出来.

当前页面, 就显示, 不是当前页面, 则 display:none


没错. 在 Blazor 的 Render 系统里 , 只有输出了, 才有生命. 不输出, 就会被系统释放.

以是, 所有要让它在世的 Page , 都得输出. 哪怕用display:none隐藏它.


看看视频效果吧.

https://www.bilibili.com/video/BV1g54y1R7uX/

 

最后:

github : https://github.com/BlazorPlus/BlazorDemoKeepPageState 

视频杂音简直多, 求推荐一个...

 

,

Sunbet 申博

Sunbet 申博www.99ruxian.com女性健康网,免费提供女性保健常识、女性饮食、女性疾病、女性心理、女性情感、女性用品、女性孕育等女性健康知识。

转载声明:本站发布文章及版权归原作者所有,转载本站文章请注明文章来源!

本文链接:https://www.guangxianchuangan.com/post/725.html

网友评论