Blazor University (21)使用 RenderFragments 模板化組件 —— 傳遞占位符

原文鏈接:https://blazor-university.com/templating-components-with-renderfragements/passing-placeholders-to-renderfragments/

將占位符傳遞給 RenderFragments

源代碼[1]

說明:此頁面的靈感來自用戶 ?ister?agoo 的 Twitter 帖子。

首先,聲明 RenderFragment<RenderFragment> 類型的 [Parameter] 屬性可能看起來不直觀,或者可能有點奇怪。

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

事實上,如果您曾經創建過自定義 Blazor 布局,那么您已經熟悉了類似的概念。

RenderFragment<T> 中的 <T> 作為 @context 變量傳遞給用戶指定的標記。布局使用名稱 @Body 而不是 @context,但 @Body 實際上是一個 RenderFragment。為了證明這一點,編輯 /Shared/MainLayout.razor 文件并將 @Body 更改為以下內容。

@Body.GetType().Name

現在我們將看到類名,而不是顯示 @Body 渲染的內容,它恰好是 RenderFragment

雖然這并不是 Blazor 布局的工作原理,但它是一個有用的比較,有助于理解聲明 RenderFragment<RenderFragment> 類型的 [Parameter] 屬性背后的原理。

<div?class="our-main-layout">@Body
</div>

在前面的虛構布局中,我們可以將整個標記想象為某個父組件的 ChildContent RenderFragment,而第 3 行的 @Body 相當于 @context(命名為 Body),我們可以選擇在我們希望的任何地方注入。在本示例中,我們選擇將 Body 注入 HTML <div> 元素中。。

對應的等價代碼

<OurComponent><p>@context</p>
</OurComponent>

或者,如果我們想使用名稱 Body(或任何其他名稱) 而不是上下文,我們可以指定用于上下文的名稱。請參閱將數據傳遞給 RenderFragment[2] 末尾的避免 @context 名稱沖突部分。

<OurComponent?Context="FragmentWeNeedToRender"><div?class="our-wrapped-fragment">@FragmentWeNeedToRender</div>
</OurComponent>

創建一個工作示例

首先,創建一個我們可以用來綁定一些數據的類。

public?class?Person
{public?string?Salutation?{?get;?set;?}public?string?GivenName?{?get;?set;?}public?string?FamilyName?{?get;?set;?}
}

創建一個簡單的模板化重復組件

此詳細信息類似于使用 @typeparam 創建通用組件[3]一節中介紹的內容。

接下來,我們需要在 /Shared 中創建一個名為 DataList.razor 的新組件。該組件將是一個通用組件(使用 @typeparam),并將采用一個 IEnumerable<TItem> 并迭代可枚舉以使用其使用者指定的模板呈現每個項目的內容。

@typeparam?TItem
<ul>@foreach?(TItem?item?in?Data????Array.Empty<TItem>()){@ItemTemplate(item)}
</ul>
@code
{[Parameter]public?IEnumerable<TItem>?Data?{?get;?set;?}[Parameter]public?RenderFragment<TItem>?ItemTemplate?{?get;?set;?}
}

這個組件可能會被我們的 Index 頁面使用,如下所示:

@page?"/"<DataList?Data=@Data><ItemTemplate><li?@key=context>@context.Salutation?@context.GivenName?@context.FamilyName</li></ItemTemplate>
</DataList>@code
{private?IEnumerable<Person>?People;protected?override?void?OnInitialized(){base.OnInitialized();People?=?new?Person[]{new?Person?{?Salutation?=?"Mr",?GivenName?=?"Bob",?FamilyName?=?"Geldof"?},new?Person?{?Salutation?=?"Mrs",?GivenName?=?"Angela",?FamilyName?=?"Rippon"?},new?Person?{?Salutation?=?"Mr",?GivenName?=?"Freddie",?FamilyName?=?"Mercury"?}};}
}

注意: <li> 元素中的 @key=context 用于優化性能,應在呈現列表時使用。有關更多信息,請參閱使用 @key 進行優化[4]

問題

如果我們的 DataList 組件不僅輸出項目列表怎么辦。也許它有一個頁腳,允許用戶使用“上一個”/“下一個”按鈕一次顯示一頁元素,還有一個頁腳顯示總共有多少項目?

我們可以簡單地將這個額外的標記添加到我們的 DataList 組件中,但是如果我們的組件的使用者也想要以不同的方式呈現列表怎么辦?也許他們需要在一個地方將分頁列表顯示為 HTML <table>,而在其他地方顯示 HTML <ul>

<div?class="paged-data-list"><div?class="paged-data-list_header">@Data.Count()?item(s)</div><div?class="paged-data-list_body"><!--?Consumer?wants?either?a?<table>?or?a?<ul>?here?-->@foreach(TItem?item?in?CurrentPageOfData){@ItemTemplate(item)}<!--?Consumer?wants?either?a?</table>?or?a?</ul>?here?--></div><div?class="paged-data-list_footer"><button?type="button"?etc>Prev</button><button?type="button"?etc>Next</button>?</div>
</div>

這正是需要我們讓用戶傳入 RenderFragment<RenderFragment> 的原因。

在 RenderFragment 中渲染 RenderFragment

現在我們的 ItemTemplate 接收了 Person 類型的 @context 以呈現每個元素,我們需要允許我們的組件的使用者指定在第一個元素之前和最后一個元素之后要包含的內容 - 如前面的代碼中突出顯示的那樣第 6 行和第 11 行的示例。

組件使用代碼看起來類似于以下兩個示例中的任何一個

<DataList?Data=@People><ItemTemplate?Context="person"><li?@key=person>@person.Salutation?@person.FamilyName,?@person.GivenName</li></ItemTeplate>
</DataList><DataList?Data=@People><ListTemplate?Context="allPeople"><ul?Type="A">@allPeople</ul></ListTemplate><ItemTemplate?Context="person"><li?@key=person>@person.Salutation?@person.FamilyName,?@person.GivenName</li></ItemTemplate>
</DataList>
  • 第 2 行

    定義要用于列表的模板。在這種情況下,我們用 <ul></ul> 包裝我們的內部內容(我們的數據項“allPeople”)。

  • 第 4 行

    執行通過我們選擇稱為“allPeople”的上下文變量傳遞的 RenderFragment 來指示在何處渲染項目標記。

  • 第 7 行

    為每個項目指定一個模板。在這種情況下,上下文將是 Person 的一個實例,因此我們選擇通過指定 Context="person" 以名稱“person”來引用上下文。

將渲染的內容作為占位符傳遞給消費者顯示

DataList 組件需要呈現 Data 屬性中的每個項目,然后將其傳遞給使用者以決定在其 ListTemplate 中的哪個位置呈現該輸出。或者,更準確地說,DataList 需要傳遞一個 RenderFragment,它會在執行時呈現項目的標記。

首先,我們將 ListTemplate 屬性添加到我們的 DataList 組件中。

[Parameter]
public?RenderFragment<RenderFragment>?ListTemplate?{?get;?set;?}

接下來,我們將更改我們的 DataList,以便當消費者沒有指定 ListTemplate 時它使用 <ul><li> 作為默認值,之后我們將處理組件使用者確實想要使用自定義 ListTemplate 的場景.

使用默認列表模板進行渲染

這是簡單的部分。我們需要做的就是編寫我們的標記,就好像組件上沒有 ListTemplate 這樣的東西,就像我們通常那樣——但前提是 ListTemplate 屬性為空。

@typeparam?TItem
@if?(ListTemplate?==?null)
{<ul>@foreach?(TItem?item?in?Data????Array.Empty<TItem>()){@ItemTemplate(item)}</ul>
}@code
{[Parameter]public?IEnumerable<TItem>?Data?{?get;?set;?}[Parameter]public?RenderFragment<TItem>?ItemTemplate?{?get;?set;?}[Parameter]public?RenderFragment<RenderFragment>?ListTemplate?{?get;?set;?}
}
  • 第 2 行

    檢查 ListTemplate 是否為空

  • 第 4-9 行

    如果 ListTemplate 為 null,那么我們渲染一個標準的 <ul> 列表,然后使用 ItemTemplate 渲染 Data 中的元素。

使用自定義 ListTemplate 進行渲染

RenderFragment<TItem> 期望我們在每次渲染它時傳遞一個 TItem 實例。這很簡單,因為我們有一個 IEnumerable<TItem> ,我們可以從中提取要渲染的值,但是當我們需要將 RenderFragment 的實例傳遞給我們的模板時該怎么辦?

要定義非泛型 RenderFragment,我們可以使用標準 Razor 轉義序列來表示 HTML,即@

RenderFragment?rf?=?@<h1>Hello</h1>;

要定義 RenderFragment<T>,我們需要使用傳入 T 實例的 lambda 表達式

RenderFragment<Person>?rf?=?person?=>?@<h1>Hello?@person.Name</h1>;

那么我們如何返回一個 RenderFragment,它只會在渲染時循環遍歷 Data 屬性中的項目?為此,我們需要使用 wig-pig 語法。

wig-pig

wig-pig 是 Razor 渲染引擎可用于表示 C# 文件中的 Razor 標記塊的一組字符。出于顯而易見的原因,此字符序列僅適用于 .razor 文件。如有雷同,純屬巧合。

注意: @:@{ 實際上是兩個字符序列。第一個 @: 告訴 Razor 解析器將以下文本視為 Razor 標記,然后 @{ 是 C# 代碼塊的開始——它顯然會在某個地方以補充 } 結束。最終,這給了我們一大塊 Razor 標記,它相當于一個帶有 C# 代碼的 RenderFragment,它可以執行諸如循環之類的操作。

在 Razor 文件中調用 @ListItem(...) 時,我們可以使用 wig-pig 語法將 RenderFragment 作為參數傳遞。

@ListTemplate(@:@{foreach?(TItem?item?in?Data????Array.Empty<TItem>()){@item.ToString()}}
)

使用這種語法,我們渲染組件使用者在 <ListTemplate> 中指定的標記,并傳入一個 RenderFragment,該 RenderFragment 將渲染 Data 中的所有元素。在前面的代碼中,它只是對 Data 中的每個項目調用 ToString()。但是,理想情況下,我們希望組件使用者為我們提供的 ItemTemplate

@ListTemplate(@:@{foreach?(TItem?item?in?Data????Array.Empty<TItem>()){@ItemTemplate(item)}}
)

DataList.razor

@typeparam?TItem
@if?(ListTemplate?==?null)
{<ul>@foreach?(TItem?item?in?Data????Array.Empty<TItem>()){@ItemTemplate(item)}</ul>
}
else
{@ListTemplate(@:@{foreach?(TItem?item?in?Data????Array.Empty<TItem>()){@ItemTemplate(item)}})
}@code
{[Parameter]public?IEnumerable<TItem>?Data?{?get;?set;?}[Parameter]public?RenderFragment<TItem>?ItemTemplate?{?get;?set;?}[Parameter]public?RenderFragment<RenderFragment>?ListTemplate?{?get;?set;?}
}

使用我們的 DataList

示例 1:一個簡單的列表

<DataList?Data=@People><ItemTemplate><li?@key=context>@context.Salutation?@context.GivenName?@context.FamilyName</li></ItemTemplate>
</DataList>

生成以下 HTML

<ul><li>Mr?Bob?Geldof</li><li>Mrs?Angela?Rippon</li><li>Mr?Freddie?Mercury</li>
</ul>

bbdde780ff1b8d2b97f39a093be0dc8c.png

示例 2:一個 HTML 表格

<DataList?Data=@People><ListTemplate?Context="listOfPeople"><table?border=1?cellpadding=4><thead><tr><th>Salutation</th><th>Given?name</th><th>Family?name</th></tr></thead><tbody>@listOfPeople</tbody></table></ListTemplate><ItemTemplate?Context="person"><tr?@key=@person><td>@person.Salutation</td><td>@person.GivenName</td><td>@person.FamilyName</td></tr></ItemTemplate>
</DataList>

生成以下 HTML

<table?cellpadding="4"?border="1"><thead><tr><th>Salutation</th><th>Given?name</th><th>Family?name</th></tr></thead><tbody><tr><td>Mr</td><td>Bob</td><td>Geldof</td></tr><tr><td>Mrs</td><td>Angela</td><td>Rippon</td></tr><tr><td>Mr</td><td>Freddie</td><td>Mercury</td></tr></tbody>
</table>

780ed50b713b259c11a14819c9df04fe.png

未指定 RenderFragments 時分配默認值

目前,我們必須在視圖中使用 @if 語句檢查 ListTemplate 是否為 null,我們甚至沒有檢查 ItemTemplate 是否已設置。這些方法都不是理想的。

相反,如果組件使用者沒有設置我們的 RenderFragment 屬性,我們應該將它們設置為所需的默認值。這樣我們組件的渲染邏輯就可以變得更加簡單。

@ListTemplate(@:@{foreach(TItem?item?in?CurrentPage){@ItemTemplate(item)}}
)

在我們的組件中重寫 OnParametersSet() 并確保 ItemTemplate 屬性不為空。為此,我們創建一個接收 TItem 并返回 RenderFragment 的 lambda(使用 wig-pig 語法)。

protected?override?void?OnParametersSet(){if?(ItemTemplate?==?null){ItemTemplate?=?(item)?=>?@:@{?<li?@key=item>@item.ToString()</li>};}
}

為了確保 ListTemplate 不為空,我們創建了一個接收 RenderFragment 的 lamba,并返回我們自定義的 wig-pig RenderFragment

if?(ListTemplate?==?null){ListTemplate?=?_?=>?@:@{?<ul>@foreach(TItem?item?in?CurrentPage){@ItemTemplate(item)}</ul>};}

注意: ;不能與前面的 } 在同一行,否則 Razor 解析器無法正確解析源。這已被報告為一個錯誤,并有望在不久的將來得到修復。

總結

當組件使用者希望在其標記中為將在渲染期間傳遞給他們的內容識別占位符時,應使用 RenderFragment<RenderFragment> 技術 - 例如 Blazor 布局中的 Body 占位符。

希望本節可以幫助您了解何時使用此技術,以及如何使用 wig-pig @:@{ 語法來就地生成 RenderFragments

補充閱讀

本節的源代碼包括一個使用 `PagedDataList` 組件[5]的附加示例頁面。

參考資料

[1]

源代碼: https://github.com/mrpmorris/blazor-university/tree/master/src/TemplatedComponents/PassingPlaceholdersToRenderFragments

[5]

使用 PagedDataList 組件: https://github.com/mrpmorris/blazor-university/blob/master/src/TemplatedComponents/PassingPlaceholdersToRenderFragments/Shared/PagedDataList.razor

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287550.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287550.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287550.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

物聯網(車聯網)平臺架構方案

技術支持QQ&#xff1a;787728951、車載終端網關采用mina/nettyspring架構&#xff0c;獨立于其他應用&#xff0c;主要負責維護接入終端的tcp鏈接、上行以及下行消息的解碼、編碼、流量控制&#xff0c;黑白名單等安全控制&#xff0c;網關同時支持交通部JT/T808-2011、JT/T80…

[python opencv 計算機視覺零基礎到實戰] 八、ROI泛洪填充

一、學習目標 了解什么是ROI了解floodFill的使用方法 如有錯誤歡迎指出~ 目錄 [python opencv 計算機視覺零基礎到實戰] 一、opencv的helloworld [【python opencv 計算機視覺零基礎到實戰】二、 opencv文件格式與攝像頭讀取] 一、opencv的helloworld [[python opencv 計…

【經典回放】JavaScript學習詳細干貨筆記之(二)

【經典回放】JavaScript學習詳細干貨筆記之(一) 【經典回放】JavaScript學習詳細干貨筆記之(二) 【經典回放】JavaScript學習詳細干貨筆記之(三) 一、JavaScript 數組 JavaScript數組的定義、使用都是非常簡單的,從a17.htm就可以知道,僅僅定義的話,就使用: var …

java string類api_java基礎—String類型常用api

1、字符串比較equalsequalsIgnoreCase 忽略大小寫做比較2、字符串拆分(切片)splitString a "lemon:python:Java";//split切片之后的結果是一個一維字符串類型數組String[] arr a.split(":");for(int i 0 ;i System.out.println(arr[i]);}3、字符串截取…

解決沖突

人生不如意之事十之八九&#xff0c;合并分支往往也不是一帆風順的。 準備新的feature1分支&#xff0c;繼續我們的新分支開發&#xff1a; $ git checkout -b feature1 Switched to a new branch feature1修改readme.txt最后一行&#xff0c;改為&#xff1a; Creating a new …

Android之java.lang.OutOfMemoryError: Failed to allocate a ** byte allocation with **free bytes and 2M

1 問題 glide加載圖片出現oom java.lang.OutOfMemoryError: Failed to allocate a 23970828 byte allocation with 2097152 free bytes and 2MB until OOM 2 解決辦法 1) 簡單粗暴點的在AndroidManifest.xml添加如下&#xff0c;增大安卓虛擬機內存 android:largeHeap"…

HQL入門學習

2019獨角獸企業重金招聘Python工程師標準>>> package myHibernate; /** 測試簡單的HQL語句* 2010年4月9日 23:36:54* */ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.uti…

Oracle精簡客戶端配置

2019獨角獸企業重金招聘Python工程師標準>>> 由于Oracle client體積很大。而且安裝后&#xff0c;基本上就用2個功能&#xff1a;TNS配置服務名和SQL*Plus。下面是一種小巧、快捷的Oracle客戶端配置方法&#xff1a; 1.下載Instant Client 下載地址&#xff1a; htt…

【經典回放】JavaScript學習詳細干貨筆記之(三)

【經典回放】JavaScript學習詳細干貨筆記之(一) 【經典回放】JavaScript學習詳細干貨筆記之(二) 【經典回放】JavaScript學習詳細干貨筆記之(三) 一、再次從var開始說起 var到底是什么? 在前面的所有介紹中, JavaScript的var變量說明、是非常令人迷惑的事情。 var中…

WinUI遷移到.NET MAUI個人體驗

遷移的初衷本人平時是做.net相關的工作&#xff0c;對于.net技術棧也有一些了解&#xff0c;自從新的.net能夠跨平臺之后&#xff0c;之前也有跨平臺的ui框架Xamarin&#xff0c;現在微軟推出了.NET MAUI這個說是 統一了開發體驗&#xff0c;而且都RC版本了&#xff0c;所以本人…

祝CSDN2021牛氣沖天祝我也撥云散霧

前言 2020年4月&#xff0c;我寫了一篇用turtle繪制《小清新風格的樹》&#xff0c;反響挺好。現在打算使用turtle修改一下繪制方式&#xff0c;因為線條的繪制太過考慮因素過多&#xff0c;如果使用方塊進行堆疊&#xff0c;繪制出來的形狀可以如馬賽克一樣&#xff0c;既符合…

Android之Only fullscreen opaque activities can request orientation

1 問題 使用透明的activity主題&#xff0c;并且固定了方向&#xff0c;在Android8.0手機上提示錯誤如下 Only fullscreen opaque activities can request orientation 2 解決辦法 簡單粗暴就是去在AndroidManifest.xml文件去掉當前activity配置的里面的橫豎屏方向設置 and…

wamp5.5.12安裝re dis擴展

轉載地址&#xff1a;http://hanqunfeng.iteye.com/blog/1984387 phpredis是個人覺得最好的一個php-redis客戶端&#xff0c;因為其提供的function與redis的命令基本一致&#xff0c;降低的了學習成本&#xff0c;同時功能也很全面。 一。linux安裝方法 phpredis下載地址&#…

java 數組轉bean_json數組轉java對象怎么轉

展開全部首先需要 commons-beanutils jar包&#xff0c;然后轉bean的方法為&#xff1a;62616964757a686964616fe59b9ee7ad9431333363386133/**** Title: transMap2Bean* param&#xff1a;param map* param&#xff1a;param obj* return&#xff1a;void* Description&#x…

FPGA圖案--數字表示(代碼+波形)

在數字邏輯系統&#xff0c;僅僅存在高低。所以用它只代表一個整數數字。并且有3代表性的種類。這是&#xff1a;原碼表示(符號加絕對值值)、反碼表示(加-minus標志)而補碼(符號加補)。這三個在FPGA中都有著廣泛的應用。以下分別討論。1、原碼表示法 原碼表示法是機器數的一種簡…

WPF效果第一百八十四篇之網頁視頻保存

一年一度的小學入學采集開始了;我一朋友很是頭大,他說頭都大了好幾圈了;既要準備各種入學材料又要聽線上專人視頻直播講解;然而在直播結束后,他發現自己仍是一臉疑惑;雖說直播有回訪吧,但是他那蝸牛網速簡直了;這時他場外找我,讓我看能不能給他自己下載一份;1、畢竟第一次,直接…

【遙感數字圖像處理】基礎知識:第一章 緒論

第一章 緒 論 ◆ 課程學習要求 主要教學內容&#xff1a;遙感數字圖像處理的概念和基礎知識&#xff0c;遙感數字圖像的幾何處理&#xff0c;遙感圖像的輻射校正&#xff0c;遙感數字圖像的增強處理&#xff0c;遙感圖像的計算機分類&#xff0c;遙感數字圖像的分析方法&…

Android之Canvas的drawRoundRect()

1 問題 Canvas的drawRoundRect()函數怎么用 public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) 功能:該方法用于在畫布上繪制圓角矩形,通過指定RectF對象以及圓角半徑來實現。float rx:生成圓角的橢圓的X軸半徑 float ry:生成圓角的橢圓的Y軸半徑…

201671010128 2017-10-08《Java程序設計》之Lambda與內部類

一、基本概念 Java Lambda 表達式是 Java 8 引入的一個新的功能&#xff0c;主要用途是提供一個函數化的語法來簡化編碼。Lambda表達式本質上是一個匿名方法。Java Lambda 表達式以函數式接口為應用基。內部類(inner class)是定義在另一個類內部的類。二、幾點注意 使用內部類的…

自定義Git

在安裝Git一節中&#xff0c;我們已經配置了user.name和user.email&#xff0c;實際上&#xff0c;Git還有很多可配置項。 比如&#xff0c;讓Git顯示顏色&#xff0c;會讓命令輸出看起來更醒目&#xff1a; $ git config --global color.ui true這樣&#xff0c;Git會適當地顯…