日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

Blazor 服务端组件 Render, RenderFragment ,RenderTreeBuilder, CascadingValue/CascadingParameter

發(fā)布時(shí)間:2023/12/13 综合教程 29 生活家
生活随笔 收集整理的這篇文章主要介紹了 Blazor 服务端组件 Render, RenderFragment ,RenderTreeBuilder, CascadingValue/CascadingParameter 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、組件

支撐Blazor的是微軟的兩大成熟技術(shù),Razor模板和SignalR,兩者的交匯點(diǎn)就是組件。通常,我們從ComponentBase派生的類型,或者創(chuàng)建的.razor 文件,就可以稱作組件。基于這兩大技術(shù),組件也就具備了兩大功能,1、生成html片段;2、維護(hù)組件狀態(tài)。這里我們來(lái)說(shuō)一下組件最基本的功能,生成html片段。

二、RenderTreeBuilder,RenderFragment

我們知道,瀏覽器處理HTML 文檔時(shí)會(huì)將所有的標(biāo)簽都掛到一顆文檔樹中,無(wú)論一段HTML來(lái)自哪里,總會(huì)被這棵樹安排的明明白白。換句話說(shuō),如果有根線的話,我們可以依靠這棵樹把所有的標(biāo)簽都串起來(lái),而在Blazor組件中也有這么一根線,這根線就是RenderTreeBuilder,拿這根線的人就是Blazor框架。

備注一下:以下涉及的代碼如果沒(méi)有特別說(shuō)明,都是指寫在.cs文件中,繼承 Microsoft.AspNetCore.Components.ComponentBase 的組件類。

下面用代碼看看這根線。 新建一個(gè)Blazor 應(yīng)用 項(xiàng)目,新增 一個(gè)c#類,MyComp 繼承 Microsoft.AspNetCore.Components.ComponentBase,然后override 一下,找到如下方法:

 protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            base.BuildRenderTree(builder);//加斷點(diǎn)
        }

加個(gè)斷點(diǎn),在項(xiàng)目的 PagesIndex.razor 里加上一行。<MyComp />
如果不想代碼執(zhí)行兩次,就在Pages_Host.cshtml 里修改一下rendermode

 @(await Html.RenderComponentAsync<App>(RenderMode.Server))

F5跑起來(lái),雖然沒(méi)有任何輸出,但是斷點(diǎn)命中了,RenderTreeBuilder這根線確實(shí)串起了我們的組件。
現(xiàn)在讓我們看看,RenderTreeBuilder 可以做什么。

  protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, "<span> BuildRenderTree  使用 AddMarkupContent 輸出 Html 。</span>");
           // base.BuildRenderTree(builder);
        }

再次跑起來(lái),我們發(fā)現(xiàn)頁(yè)面上多了我們加的span.也就是說(shuō)HTML的輸出,靠的是調(diào)用RenderTreeBuilder上的各種方法加上的。組件的基本原理也就是這樣,一個(gè)RenderTreeBuilder 進(jìn)入不同組件的 BuildRenderTree 方法,方法內(nèi) 通過(guò)RenderTreeBuilder上的add.. open.. 方法把我們想要輸出的部分,掛載到builder上,最終輸出到瀏覽器。

接下來(lái),我們考察一下BuildRenderTree方法, 用委托描述一下,我們發(fā)現(xiàn)這就是一個(gè)Action<RenderTreeBuilder>.

在標(biāo)題里我們提到了RenderFragment, 查看一下它的定義。

public delegate void RenderFragment(RenderTreeBuilder builder);//還是一個(gè) Action<RenderTreeBuilder>,或者說(shuō),BuildRenderTree 就是一個(gè)RenderFragment

我們發(fā)現(xiàn)和前面的BuildRenderTree 在簽名上一模一樣,既然blazor會(huì)使用RenderTreeBuilder 去調(diào)用BuildRenderTree 方法,那么RenderFragment會(huì)不會(huì)也被調(diào)用?

讓我們暫時(shí)離開組件MyComp,轉(zhuǎn)到Index.razor 內(nèi)加一段code

 @code{
     RenderFragment MyRender=(builder) => builder.AddMarkupContent(0, "<span>當(dāng)前輸出來(lái)自:Index.razor 組件, MyRender 字段。 </span>");
        
}

在之前我們聲明 MyComp組件之后,再加一行調(diào)用 @MyRender.
完整的Index.razor

@page "/"

<MyComp />

 @MyRender

@code{
     
    RenderFragment MyRender = (builder) => builder.AddMarkupContent(0, "<div>當(dāng)前輸出來(lái)自:Index.razor 組件, MyRender 字段。 </div>");

}

兩段信息,如愿輸出,證明blazor能夠識(shí)別出模板中的 RenderFragment ,并自動(dòng)調(diào)用。
既然我們?cè)诮M件模板中(Index.razor)書寫RenderFragment ,當(dāng)然有其他方式可以不用拼湊字符串。

 RenderFragment AnotherRender =@<div>模板寫法的RenderFragment</div>;

加上調(diào)用 @AnotherRender,跑起來(lái),三段信息。

至此,我們對(duì)RenderFragment 有了一個(gè)大概的了解,它是一個(gè)函數(shù),內(nèi)部打包了我們的輸出內(nèi)容。在模板中我們可以使用,@xxxrender將其就地展開輸出,在c#環(huán)境下我們可以通過(guò) xxxrender(builder)的形式進(jìn)行調(diào)用(比如在BuildRenderTree方法內(nèi)調(diào)用)。又因?yàn)槠浔旧砭褪且粋€(gè)委托函數(shù),因此我們即可以在組件內(nèi)使用,也可以自由的在組件之間傳遞, 完成對(duì)輸出內(nèi)容及邏輯的復(fù)用。
同時(shí),為了更好的配合RenderFragment 使用,Blazor中還提供了一個(gè)工廠委托,RenderFragment , 即 Func<TValue,RenderFragment> 用法一般如下

//模板中(Index.razor)
RenderFragment<object> RenderValue =value=> @<div> render value :@value</div>;

調(diào)用 @RenderValue (123) 如果在c#代碼中,比如在BuildRenderTree 方法內(nèi), RenderValue (123)(builder)

vs中*.razor在編譯時(shí)會(huì)生成對(duì)應(yīng)的.g.cs代碼,位置在obj/debug/netcoreapp3.0/ razor 下,可以多打開看看。

三、RenderFragment 的一些用法

1、html中,我們可以在一對(duì)標(biāo)簽內(nèi)添加 內(nèi)容,比如 <div>123</div>,組件默認(rèn)是不支持此類操作的,這時(shí)我們就需要RenderFragment來(lái)包裝標(biāo)簽內(nèi)的內(nèi)容。

讓我們回到MyComp組件類中,增加一個(gè)屬性

[Parameter] public RenderFragment ChildContent{ get; set; }

Index.razor

<MyComp><div> 組件標(biāo)記內(nèi)部</div></MyComp>

此時(shí)直接運(yùn)行的話,組件不會(huì)輸出內(nèi)部信息,需要在BuildRenderTree 中執(zhí)行一下

  protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
          ChildContent?.Invoke(builder);
          
            base.BuildRenderTree(builder);
        }

組件標(biāo)記內(nèi)的片段被打包進(jìn)了 ChildContent,已經(jīng)變成了獨(dú)立的一個(gè)片段,因此需要我們顯式的調(diào)用一下。
ChildContent 是特殊名稱

2、組件上有多個(gè)RenderFragment

   [Parameter] public RenderFragment Fragment1 { get; set; }
        [Parameter] public RenderFragment Fragment2 { get; set; }

此時(shí)調(diào)用需要調(diào)整一下,不然框架不知道把內(nèi)容片段打包進(jìn)哪個(gè)屬性里

 <MyComp>
        <Fragment1>

            <div> Fragment1 </div>
        </Fragment1>
        <Fragment1>
            <div> Fragment1.1  </div>

        </Fragment1>
        <Fragment2>
            <div> Fragment2  </div>

        </Fragment2>
  
    </MyComp>

這里故意重復(fù)處理了Fragment1,可以看看結(jié)果。

3、帶參數(shù)的RenderFragment
code:

[Parameter] public RenderFragment<MyComp> ChildContent { get; set; }

調(diào)用及傳參

  <MyComp Context="self" > //<ChildContent>
       @self.GetType()
      
    </MyComp>  //</ChildContent>

4、打開的組件聲明標(biāo)記內(nèi)部,除了可以使用RenderFragment 參數(shù)屬性外,其他的razor 語(yǔ)法基本都支持,也包括另外一個(gè)組件。
比如

  <MyComp>
         <CompA />
          <CompB> ...... </CompB>
</MyComp>

或者

  <MyComp>
       <Fragment1>
         <CompA />
      </Fragment1>

          <Fragment2>
          <CompB> ...... </CompB>
          </Fragment2>
</MyComp>

雖然看上去,聲明標(biāo)記的代碼很相似,但卻有著實(shí)質(zhì)上的不同。
當(dāng)我們使用 標(biāo)記聲明一個(gè)參數(shù)屬性時(shí),我們是在生成RenderFragment,隨后將其賦值給對(duì)應(yīng)的屬性。
當(dāng)我們使用標(biāo)記聲明一個(gè)組件時(shí),我們是在構(gòu)造一個(gè)組件實(shí)例,然后調(diào)用它,將組件輸出插入到組件所在位置。
參數(shù)屬性(RenderFragment )屬于組件,是組件的一個(gè)屬性,互相關(guān)系是明確的類型《=》成員關(guān)系。
組件內(nèi)部的其他組件標(biāo)記很多時(shí)候只是為了復(fù)用一些輸出片段,如果不通過(guò)代碼進(jìn)行一些處理的話,是無(wú)法明確知道組件之間關(guān)系的。

四、CascadingValue/CascadingParameter

組件多起來(lái)之后,組件之間的數(shù)據(jù)共享和傳遞以及組件間的關(guān)系就會(huì)變的很麻煩,數(shù)量少的時(shí)候,還可以使用@ref 手工指定,多起來(lái)之后@ref明顯不是一個(gè)好方法。 組件CascadingValue和對(duì)應(yīng)的特性[CascadingParameter]就是為了解決這一問(wèn)題而出現(xiàn)。

一個(gè)CascadingValue 內(nèi)的所有組件 包括子級(jí),只要組件屬性上附加了[CascadingParameter]特性,并且值內(nèi)容可以兼容,此屬性就會(huì)被賦值。

比如給組件定義 屬性接收CascadingValue

        [CascadingParameter] public  int Value { get; set; }
        [CascadingParameter] public string SValue { get; set; }

//修改下輸出
    protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, $"<div>CascadingValue: {Value},{SValue} </div>");// 一個(gè)int,一個(gè)string
            ChildContent?.Invoke(this)(builder);//加載下級(jí)組件
            base.BuildRenderTree(builder);
        }

在razor頁(yè)中

 <CascadingValue Value="123"> //int
      <MyComp>
                         <MyComp></MyComp>
                     </MyComp>
</CascadingValue >

執(zhí)行后我們就會(huì)發(fā)現(xiàn),兩個(gè)組件都捕獲到了int 值 123.
現(xiàn)在再加一個(gè)CascadingValue

 <CascadingValue Value="123"> //int
<CascadingValue Value="@("aaaa")"> //string
      <MyComp>
                         <MyComp></MyComp>
                     </MyComp>
</CascadingValue >
</CascadingValue >

分屬兩個(gè)CascadingValue 的兩個(gè)不同類型值,就被每個(gè)組件的兩個(gè)屬性捕獲到,方便、強(qiáng)大而且自身不產(chǎn)生任何HTML輸出,因此使用場(chǎng)景非常廣泛。比如官方Forms組件中就是借助CascadingValue/Parameter 完成model的設(shè)置,再比如,組件默認(rèn)沒(méi)有處理父子、包含關(guān)系的接口,這時(shí)就可以簡(jiǎn)單的定義一個(gè)[CascadingParameter] public ComponentBase Parent{get;set;}專門接收父級(jí)組件,處理類似Table/Columns之類的組件關(guān)系。

五、總結(jié)

組件是為其自身的 BuildRenderTree方法 ( RenderFragment )服務(wù)的,組件上的各種屬性方法,都是為了給RenderFragment 做環(huán)境準(zhǔn)備,因此組件實(shí)質(zhì)上是個(gè)RenderFragment的包裝類。組件系統(tǒng)則通過(guò)一個(gè)RenderTreeBuilder依次調(diào)用各組件,收集輸出內(nèi)容,最終交給系統(tǒng)內(nèi)部完成輸出。
1、.Razor文件會(huì)被編譯為一個(gè)組件類(obj/debug/netcore3.0/razor/...)
2、組件系統(tǒng)創(chuàng)建RenderTreeBuilder,將其交給組件實(shí)例
3、組件實(shí)例使用 RenderTreeBuilder,調(diào)用自身 BuildRenderTree。
4、等待組件狀態(tài)變化,再次輸出。

原文連接:https://www.cnblogs.com/cerl/p/11834510.html

總結(jié)

以上是生活随笔為你收集整理的Blazor 服务端组件 Render, RenderFragment ,RenderTreeBuilder, CascadingValue/CascadingParameter的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。