原文地址:http://asp.net-hacker.rocks/2016/02/18/extending-razor-views.html
作者:Jürgen Gutsch
翻譯:楊曉東(Savorboard)
現在,已經有很多種方式來擴展Razor視圖了,我們循循漸進,先從最簡單的開始。
如果你之前熟悉MVC5(以及之前的MVC)中的視圖的話,有一部分你應該已經很熟悉了。在新的ASP.NET Core 中,那些你熟悉的方式有一部分仍然能用,只是Core版本針對視圖又添加了一些東西。這篇文章,我們就來一起看看吧。
#1:數據視圖(Typed Views)
這是一個不具有動態內容的最基本的一個視圖,就是你定義一個ViewModel , 然后ViewModel具有一些默認值,在視圖上直接呈現而已。定死的ViewModel,好像不是很常見,以至于你使用Visual Studio新建一個默認的Web應用程序的話,都看不到它。它就看起來像一個*.cshtml
結尾的HTML文件,但是,cshtml文件卻是服務端可以解析的一種文件,所以你可以在里面使用一些Razor語法,比如HtmlHelpers,UrlHelpers等。同樣,你可以使用ViewBag
或者ViewData
來從Controller的Action傳輸數據到View里面,來讓它具有動態的內容。但是ViewBag
和ViewData
都是弱類型的,所以沒有智能提示,用起來略不爽。
要在你的視圖中使用強類型數據對象,你需要定義一個Model來在視圖中使用。
@model ExtendViews.ViewModels.AboutModel
<!-- usage: --->
@Model.FullName
這種方式是不是很常見的? 下一種方式是一個更好的方式來布局我們的視圖:
#2:布局(Layouts):
相當于ASP.NET的WebForms的母版頁,不過它是定義Razor視圖的基本布局的一種方式。它就是_Layout.cshtml
, 位于 Views\Shared\ 文件夾里 。通常情況下這個文件通常包含HTML的header,body和公用的一些東西。你可以多建幾個互相進行組合,來完成整個站點的布局。其他頁面引用布局視圖頁的時候,是這樣子寫的(注意不需要擴展名):
@{
Layout = "_Layout";
}
此調用需要在您的視圖的第一行中。但你不需要在每一個視圖中定義布局,如果你使用Visual Studio新建一個ASP.NET Core項目,Views文件夾有一個_ViewStart.cshtml
,在運行的時候它會自動的導入到每個視圖中去。
在_Layout.cshtml
有一個方法法叫 RenderBody()
,它就是用來渲染詳細的視圖頁到模板布局視圖中:
@RenderBody()
在此方法的位置,詳情視圖就會被渲染到這里。
#3: 區域(Sections)
有時候子視圖中想在主視圖中顯示一部分html代碼,比如javascript代碼或者是css,這個時候就可以使用Sections,通常情況下在頁面的結尾部分。
在主視圖中(_Layout.cshtml
)定義一個Javascripts Section:
@RenderSection("scripts", required: false)
有一個required參數來聲明這個Section是否必須的。然后你就可以在子視圖中這樣使用:
@section scripts
{
<script>
$(function() {
// some more js code here;
});
</script>
}
如果你使用嵌套的布局,你可能需要嵌套這個區域。意思就是你在Section里面嵌套調用RenderSection()
:
@section scripts
{
@RenderSection("scripts", required: false)
}
#4: 分部視圖( PartialViews)
你可以提取html頁面中重用的部分,把它放到一個新的Razor視圖中,這個視圖沒有自己的Action,這種視圖就叫做分部視圖。 分部視圖通常也在Views\Shard\
文件夾。
分部視圖同樣也可以是一個數據視圖,它可以從父視圖中獲取數據(但不是必須的):
@model IEnumerable<UserModel>
@if (Model.Any())
{
<ul>
@foreach (var user in Model)
{
<li>@user.FullName</li>
}
</ul>
}
這個分部視圖需要從父視圖中獲取用戶列表的數據
@{ await Html.RenderPartialAsync("Users", Model.Users);}
如果你的分部視圖沒有定義用戶模型,你就不需要傳第二個參數。
#5:視圖組件(ViewComponents)
這個 ASP.NET Core特有的。
譯者注:類似于以前的用戶控件
有時候你需要做一些分部視圖的事情,但是又包含一些業務邏輯在里面。在過去,你可以使用ChildAction渲染結果到一個視圖中,但是,在 ASP.NET Core中,有一種新的方式來做這件事情,它就是ViewComponents
(我已經寫了一篇關于ViewComponents的博文)。它類似于在MVC中的一種迷你的MVC,也就是說他們可以有自己的Controller,和單個的action以及view。ViewComponents
是完全獨立于你的當前視圖的,但是可以通過你當前的視圖傳輸數據。
想這樣調用它,來渲染一個ViewComponents
:
@Component.Invoke("Top10Articles");
可以看我的博客來學習怎么創建自己的ViewComponent
。
#6: HTML助手(HtmlHelpers)
在HTMLHelper
類中,你可以創建你自己的擴展方法來擴展Razor語法:
public static class HtmlHelperExtensions
{
public static HtmlString MyOwnHtmlHelper(this HtmlHelper helper, string message)
{
return new HtmlString($"<span>{message}<span>");
}
}
在你的視圖中,創建一個可重用的部分是非常有用的,它比分部視圖多包含了一些業務邏輯。比HTMLHelpers擴展更好的是新的TagHelpers,但是在擴展你視圖的時候,HTMLHelpers仍然有它自己的一些適用的地方。
#7: 標簽助手(TagHelper)
這是 ASP.NET Core 非常好的一個新特性。
一個擴展你視圖的小助手,它看起來像一個原生的HTML標簽一樣。 在ASP.NET Core MVC中你應該使用 TagHelpers 來替換 HtmlHelpers,因為它們更加的簡潔和容易使用。另一個巨大的好處就是依賴注入,在HtmlHelpers中是使用不了的,因為HtmlHelpers 擴展的都是靜態內容。 但TagHelpers是一個公共類,我們可以很容易的在它的構造函數中注入服務。
下面是一個很簡單的小示例,來展示怎么樣定義一個TagHelper:
[TargetElement("hi")]
public class HelloTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "p";
output.Attributes.Add("id", context.UniqueId);
output.PreContent.SetContent("Hello ");
output.PostContent.SetContent(string.Format(", time is now: {0}",
DateTime.Now.ToString("HH:mm")));
}
}
這里定義了一個叫做hi
的標簽,它以HTML標記來呈現,p標簽的內容是當前時間。
使用:
<hi>John Smith</hi>
結果:
<p>Hello John Smith, time is now: 18:55</p>
ASP.NET Core MVC 已經默認提供了很多TagHelpers來替換以前的HtmlHelpers。例如ActionLink已經被新的TagHelper所替換:
@Html.ActionLink(“About me”, “About”, “Home”)
新的TagHelper像這樣來創建一個link:
<a asp-controller=”Home” asp-action=”About”>About me</a>
以上兩種方式來創建一個a標簽的結果:
<a href=”/Home/About”>About me</a>
可以看到,TagHelpers看起來更像原生的HTML,他們在視圖中更加的直觀,更高的可讀性,并且更容易使用。
#8: 依賴注入(Dependency Injection)
這也是ASP.NET Core的新特性。
在擴展你的視圖的時候,可以使用依賴注入了,這是一個非常大改進。是的,你可以在你的視圖中使用DI了。
在StackOverflow和reddit有人這樣問?
這真的有意義嗎? 這不是會搞亂我的視圖嗎? 這不是與MVC模式背離嗎?
我認為,不是這樣的。 的確,在真正需要的地方你才使用,并且,你使用的時候需要非常小心。 有這樣一個有效的場景:你創建一個表單來編輯用戶的資料信息(User Profile), 用戶可以添加他的公司位置,地址, 國家城市等等,我不愿意從Action到View中傳輸公司位置 ,地址和國家城市。我只愿意通過用戶資料本身(User Profile), 我只想在 Action 中處理用戶資料(User Profile)。這時候可以注入服務來給我查詢數據,這就是為什么這種情況下它是非常有用的。它可以讓我們的Action和ViewModel 保持非常的干凈。
在Startup.cs
中的ConfigureServices
來注冊你具體的服務,然后你就可以在視圖中這樣來使用,只需要一行代碼:
@inject DiViews.Services.ICountryService CountryService;
現在你可以在你的視圖中使用ContryService
來填充國家下拉列表。
我在這篇博客中寫了很多關于依賴注入的博文。
#9: 函數(Functions)
在一個ASP.NET MVC 項目中,我從來沒有真正的使用過函數這個功能。我只在一個Umbraco的CMS系統中用過一次。不管怎么說,這也是擴展你視圖的另一種小技巧。也許你有很復雜視圖方面的業務邏輯,在這種情況下,你可以在你的視圖中寫C#方法:
@functions
{
public string ReverseString(string input)
{
return String.Join("", input.Reverse());
}
}
#10: 配置全局視圖(Global view configuration)
最后一點,你可以在_ViewImports.cshtml
文件中,來配置你其他視圖中使用的一些比較公用的 using 引用,依賴注入等。
總結
不管是以前的MVC還是新的Core MVC, 都有很多方法來擴展視圖,雖然擴展這些視圖的方式有些類似,但是每一種都有它最適合的地方,所以我們在使用這些特性來解決我們的問題的時候,我們應該多加思考,找到最合適的方式。
譯者注:本文翻譯并非逐字翻譯,由于水平有限,難免出現一些錯誤和翻譯不準確的地方,希望讀者能夠指出并堪正,不勝感激。
文章列表
不含病毒。www.avast.com |
留言列表