前兩篇整理完:
_Layout.cshtml
_ViewStart.cshtml
_ViewImports.cshtml
之後,我對 View 的結構終於比較有概念。
但實際繼續看專案時,又遇到兩個很容易搞混的東西:
Partial View
RenderSection
我一開始會覺得:
它們不都是把內容拆出去嗎?
那到底差在哪裡?
後來才慢慢整理出來:
Partial View
↓
把一塊局部畫面拆成另一支 .cshtml
需要時再重複使用
RenderSection
↓
Layout 先預留一個位置
讓個別 View 決定要不要把額外內容放進來
兩個看起來都跟「拆內容」有關,但實際用途其實不太一樣。
我會先這樣記:
Partial View
重點是「局部畫面」
RenderSection
重點是「Layout 的指定位置」
例如:
Header
Sidebar
共用表單區塊
共用查詢條件
使用者資訊
Modal
這些比較容易想到 Partial View。
而:
某頁專用 JavaScript
某頁專用 CSS
某頁額外區塊
這些比較容易想到 RenderSection。
先記這個方向,後面再慢慢拆。
Partial View 可以先理解成:
把一小塊畫面拆成另一支
.cshtml,需要時再由其他 View 或 Layout 引用。
例如原本 _Layout.cshtml 可能寫很多東西:
<body>
<header>
<h1>網站名稱</h1>
<nav>
<a href="/">首頁</a>
<a href="/Home/About">關於我們</a>
</nav>
</header>
<main>
@RenderBody()
</main>
</body>
如果 Header 越寫越長,就可以把它獨立拆出去。
例如建立:
Views
└── Shared
├── _Layout.cshtml
└── _Header.cshtml
_Header.cshtml:
<header>
<h1>網站名稱</h1>
<nav>
<a href="/">首頁</a>
<a href="/Home/About">關於我們</a>
</nav>
</header>
然後在 _Layout.cshtml 裡引用:
<body>
<partial name="_Header" />
<main>
@RenderBody()
</main>
</body>
這樣 Header 就被拆成一支獨立的 Partial View。

我目前會先把原因分成兩個。
假設很多頁面都有:
使用者基本資料
原本每一頁都可能寫:
<div class="user-info">
<p>姓名:...</p>
<p>Email:...</p>
<p>部門:...</p>
</div>
如果這段同時出現在:
Detail.cshtml
Edit.cshtml
Profile.cshtml
之後版型要調整,就可能要改很多次。
這時可以把它拆成:
_UserInfo.cshtml
不同 View 再引用:
<partial name="_UserInfo" />
之後如果這塊畫面要修改,就可以集中處理。
.cshtml 長到看不懂企業專案裡一個頁面可能包含很多東西:
頁面標題
查詢條件
按鈕區
表格
明細 Modal
編輯 Modal
警告區塊
如果全部塞在:
Index.cshtml
裡面,很容易變成幾百行。
這時就可能拆成:
Index.cshtml
_SearchForm.cshtml
_UserTable.cshtml
_EditModal.cshtml
然後由 Index.cshtml 組合:
<h1>使用者管理</h1>
<partial name="_SearchForm" />
<partial name="_UserTable" />
<partial name="_EditModal" />
這樣打開 Index.cshtml 時,就比較容易先看懂:
這個頁面有哪些區塊
再依照需要進到個別 Partial View 看細節。
_ 開頭嗎?不是強制。
例如常看到:
_Header.cshtml
_UserTable.cshtml
_EditModal.cshtml
前面的 _ 是很常見的命名慣例。
可以先把它理解成是在提醒開發者:
這支通常不是完整頁面
而是某種共用或局部用途的 View
但 Partial View 的用途,不是單純看檔名有沒有 _ 就能決定。
因為前面已經看過:
_Layout.cshtml
_ViewStart.cshtml
_ViewImports.cshtml
它們也都有 _,但功能完全不同。
所以:
看到 _XXX.cshtml
↓
不能直接判斷它一定是 Partial View
還是要看它實際怎麼被使用。
ASP.NET Core MVC 裡很常看到:
<partial name="_Header" />
也可能看到:
@await Html.PartialAsync("_Header")
如果 Partial View 需要自己的資料,也可以把 Model 傳進去。
例如:
<partial name="_UserInfo" model="Model.User" />
假設 _UserInfo.cshtml:
@model UserViewModel
<div class="user-info">
<p>@Model.Name</p>
<p>@Model.Email</p>
</div>
外層 Detail.cshtml:
@model UserDetailViewModel
<h1>使用者資料</h1>
<partial name="_UserInfo" model="Model.User" />
流程可以先理解成:
Detail.cshtml
↓
目前有 UserDetailViewModel
↓
把 Model.User
傳給 _UserInfo.cshtml
↓
_UserInfo.cshtml
使用自己的 UserViewModel
↓
產生使用者資訊區塊
所以 Partial View 不只是單純「把 HTML 拆出去」。
它自己也可以有:
@model
並接收外層傳進來的資料。
RenderSection 常會寫在:
_Layout.cshtml
它和 Partial View 的方向不太一樣。
Partial View 是:
我有一塊畫面
想在這裡引用進來
RenderSection 比較像:
Layout 先在某個位置留一個洞
之後讓個別 View
決定要不要把自己的內容塞進這裡
最常見的例子就是:
頁面專用 JavaScript
例如 _Layout.cshtml 可能會有:
<body>
<main>
@RenderBody()
</main>
共用 JavaScript 放在這裡
@await RenderSectionAsync("Scripts", required: false)
</body>
這裡:
@await RenderSectionAsync("Scripts", required: false)
可以先理解成:
Layout:
我在這裡預留一個叫 Scripts 的位置
↓
某個 View 如果有自己的 Scripts
↓
就放到這裡
例如 Index.cshtml:
<h1>首頁</h1>
<p>這是首頁內容。</p>
@section Scripts {
這裡放首頁專用的 JavaScript
}
這時可以拆成兩條:
Index.cshtml 的主要內容
↓
@RenderBody()
另外:
@section Scripts
↓
RenderSection("Scripts")
所以最後的頁面概念上會變成:
<body>
<main>
首頁
這是首頁內容
</main>
共用 JavaScript
首頁專用 JavaScript
</body>
所以可以記成:
@RenderBody()
↓
放目前 View 的主要內容
RenderSection("Scripts")
↓
放目前 View 額外提供的 Scripts 區塊

required: false 是什麼?例如:
@await RenderSectionAsync("Scripts", required: false)
裡面的:
required: false
代表:
Scripts 這個 Section
不是每一支 View 都一定要提供
所以某個 View 可以寫:
@section Scripts {
這裡放這一頁專用的 JavaScript
}
另外一個 View 完全不寫:
@section Scripts
也沒關係。
如果改成:
@await RenderSectionAsync("Scripts", required: true)
則代表:
使用這個 Layout 的 View
必須提供 Scripts Section
如果沒有提供,就會造成執行時的錯誤。
因為不是每一個頁面都需要額外 JavaScript,所以實際上很常看到:
required: false
假設只有:
使用者編輯頁
需要:
user-edit.js
如果直接把它當成共用 JavaScript 放進 _Layout.cshtml,那所有使用這個 Layout 的頁面都可能一起載入。
例如:
首頁
最新消息
使用者列表
報表
這些頁面根本不需要 user-edit.js。
所以比較合理的方式可以是:
site.js
↓
全站共用
↓
由 Layout 統一載入
而:
user-edit.js
↓
只有 Edit.cshtml 需要
↓
由 Edit.cshtml 的 @section Scripts 提供
也就是:
共用 JavaScript
↓
Layout
頁面專用 JavaScript
↓
@section Scripts
這也是 RenderSection 很常見的使用情境。
不是。
Scripts 只是很常見的例子。
Section 名稱其實可以自己定義。
例如 Layout 可以預留:
@await RenderSectionAsync("Styles", required: false)
某一支 View 再寫:
@section Styles {
這裡放目前頁面的專用 CSS
}
這樣就可以做到:
共用 CSS
↓
Layout 統一處理
頁面專用 CSS
↓
@section Styles
↓
放進 Layout 預留的 Styles 位置
除了:
Scripts
Styles
也可能依照專案需求看到:
Toolbar
PageHeader
Actions
之類的 Section。
所以名稱不是 ASP.NET Core 規定只能叫:
Scripts
重點是:
Layout 定義的 Section 名稱
要和 View 提供的 @section 名稱一致
這時候放在一起看就比較清楚。
| 項目 | Partial View | RenderSection |
|---|---|---|
| 主要目的 | 拆出局部畫面供其他地方引用 | 讓 View 把內容放到 Layout 指定位置 |
| 內容在哪裡 | 通常是另一支 .cshtml |
寫在目前 View 的 @section |
| 誰決定位置 | 引用 Partial 的地方 | Layout |
| 誰提供內容 | Partial View | 目前 View |
| 常見用途 | Header、表單、列表、Modal、資訊區塊 | 頁面專用 JS、CSS、Toolbar 等 |
| 可以使用 Model 嗎 | 可以 | Section 本身就是目前 View 的 Razor 內容 |
| 一定是共用內容嗎 | 不一定,但常用於拆分或重複使用 | 不一定,每個 View 可以提供不同內容 |
我自己會記成:
Partial View
「我有一塊局部畫面
想拆出去再引用」
而:
RenderSection
「Layout 有一個固定位置
讓目前 View 決定要放什麼」
假設我要做:
使用者編輯頁
可能會有:
_Layout.cshtml
↓
負責整個網站共用外框
_UserInfo.cshtml
↓
負責使用者資訊區塊
Edit.cshtml
↓
負責編輯頁主要內容
@section Scripts
↓
負責這一頁自己的 JavaScript
_Layout.cshtml:
<body>
<header>
共用 Header
</header>
<main>
@RenderBody()
</main>
共用 JavaScript
@await RenderSectionAsync("Scripts", required: false)
</body>
Edit.cshtml:
@model EditUserViewModel
<h1>編輯使用者</h1>
<partial name="_UserInfo" model="Model.User" />
<form>
...
</form>
@section Scripts {
這裡放編輯頁專用 JavaScript
}
_UserInfo.cshtml:
@model UserViewModel
<div class="user-info">
<p>姓名:@Model.Name</p>
<p>Email:@Model.Email</p>
</div>
整體關係就是:
_Layout.cshtml
↓
控制整個頁面的大框架
@RenderBody()
↓
放 Edit.cshtml 的主要內容
↓
Edit.cshtml 裡引用 _UserInfo.cshtml
↓
Partial View 顯示使用者資訊
另外:
Edit.cshtml 的 @section Scripts
↓
放進 Layout 的 Scripts Section
這樣就比較容易看出:
Partial View
和
RenderSection
其實是在處理不同方向的事情
可以。
例如:
<partial name="_Header" />
就很常直接寫在 _Layout.cshtml 裡。
所以不要把 Partial View 理解成:
只能給一般 View 使用
它其實比較像:
哪裡需要這塊局部畫面
哪裡就可以引用
例如:
_Layout.cshtml
↓
引用 _Header.cshtml
Index.cshtml
↓
引用 _SearchForm.cshtml
Edit.cshtml
↓
引用 _UserInfo.cshtml
重點是:
把局部畫面拆成獨立 View
再由需要的地方引用
現在如果碰到需求,我會先問兩個問題。
第一個:
這是一塊可以獨立出來的畫面嗎?
例如:
Header
查詢條件
卡片
使用者資訊
Modal
表格
如果是,我會先想到:
Partial View
第二個:
這是目前 View
想把某段內容放到 Layout 的特定位置嗎?
例如:
這頁專用 JavaScript
這頁專用 CSS
這頁自己的 Toolbar
這時我就會先想到:
RenderSection
所以可以縮成:
想拆出一塊局部畫面?
↓
Partial View
想讓目前 View
把內容送到 Layout 指定的位置?
↓
RenderSection
假設我在 View 裡看到:
<partial name="_SearchForm" />
但不知道內容在哪裡。
我會:
看到 _SearchForm
↓
搜尋 _SearchForm
↓
找到 _SearchForm.cshtml
↓
打開確認內容
↓
再看它有沒有 @model
如果看到:
@section Scripts {
...
}
但不知道這段內容最後會跑到哪裡。
我會反過來搜尋:
RenderSection
找到 Layout 裡:
@await RenderSectionAsync("Scripts", required: false)
再看它實際位在哪裡。
所以追法可以直接記成:
看到 <partial>
↓
找另一支 .cshtml
看到 @section
↓
往 Layout 找 RenderSection
這兩條在看陌生專案時很好用。
Partial View 很可能被很多地方引用。
所以如果修改:
_UserInfo.cshtml
不要只測目前這一頁。
我會先搜尋:
_UserInfo
看看哪些地方有引用。
可能同時出現在:
Detail.cshtml
Edit.cshtml
Profile.cshtml
這時修改 _UserInfo.cshtml,三個頁面都有可能被影響。
而如果修改 Layout 裡的:
@await RenderSectionAsync("Scripts", required: false)
影響範圍可能更大。
因為所有使用這個 Layout 的 View,都可能跟這個 Section 有關。
所以這幾天其實一直有同一個觀念:
越共用的東西
↓
修改前越要先確認影響範圍
不要只看到目前畫面正常,就以為其他頁一定沒問題。
Partial View 可以先記成:
把一塊局部畫面
拆成另一支 .cshtml
例如:
<partial name="_Header" />
常見用途像:
Header
Sidebar
表單
列表
Modal
共用資訊區塊
而 RenderSection 可以先記成:
Layout 先預留一個指定位置
↓
由目前 View
決定要不要提供額外內容
例如 Layout:
@await RenderSectionAsync("Scripts", required: false)
View:
@section Scripts {
這裡放目前頁面的專用 JavaScript
}
最簡單的判斷方式就是:
Partial View
=
我要拆出「這一塊局部畫面」
RenderSection
=
我要把「這一頁自己的額外內容」
放到 Layout 指定的位置
到這裡,前面幾天整理的 View 結構就可以完整串起來:
_ViewStart.cshtml
↓
提供 View 執行時的共用設定
最常用來指定 Layout
_ViewImports.cshtml
↓
提供 Razor 共用匯入
_Layout.cshtml
↓
提供頁面共用外框
@RenderBody()
↓
放目前 View 的主要內容
Partial View
↓
拆出局部畫面
需要時再引用
RenderSection
↓
讓目前 View
把額外內容放進 Layout 指定位置
到這裡,View 這一塊終於比較不像一開始看到的:
一堆 .cshtml 到底誰在包誰?
接下來就可以開始離開 View,往 Controller 走。
下一篇要看:
我在網址輸入
/Home/Index之後,MVC 到底怎麼知道要找到HomeController,再執行Index()?