在 ASP.NET 中,实现这种布局有几种主流方式,我会从最经典、最强大的方式讲起,再到更现代、更灵活的方式。

网页的框架 asp.net 怎么实现
(图片来源网络,侵删)

核心思想:避免重复代码

网页框架的核心目标是“Don't Repeat Yourself” (DRY),我们不希望在每个页面都写一遍 <header>, <footer>, <nav> 的 HTML 代码,ASP.NET 提供了多种机制来解决这个问题,让我们可以创建一个可复用的“模板”。


ASP.NET Web Forms (经典方式)

这是 ASP.NET 最早也是最成熟的模式,它通过 母版页 来实现框架。

母版页

母版页是一个扩展名为 .master 的特殊文件,它定义了整个网站的“骨架”和“皮肤”,它包含静态的 HTML 元素(如页头、页脚)和可替换的内容占位符。

创建步骤:

网页的框架 asp.net 怎么实现
(图片来源网络,侵删)
  1. 在 Visual Studio 中,右键项目 -> 添加 -> 新建项 -> 选择“母版页”,命名为 Site.master
  2. 你会看到一个类似普通页面的结构,但有一个特殊的 <asp:ContentPlaceHolder> 控件。

Site.master 示例代码:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="MyWebApp.SiteMaster" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head runat="server">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><%: Page.Title %> - 我的 ASP.NET 应用</title>
    <asp:PlaceHolder runat="server">
        <%: Scripts.Render("~/bundles/modernizr") %>
    </asp:PlaceHolder>
    <webopt:bundlereference runat="server" path="~/Content/css" />
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
    <form runat="server">
        <asp:ScriptManager runat="server">
            <Scripts>
                <%--To learn more about bundling and minification please visit https://go.microsoft.com/fwlink/?LinkId=301862 --%>
                <%--Framework Scripts--%>
                <asp:ScriptReference Name="MsAjaxBundle" />
                <asp:ScriptReference Name="jquery" />
                <asp:ScriptReference Name="bootstrap" />
                <asp:ScriptReference Name="respond" />
                <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
                <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
                <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
                <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
                <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
                <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
                <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
                <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
                <asp:ScriptReference Name="WebFormsBundle" />
                <%--Site Scripts--%>
            </Scripts>
        </asp:ScriptManager>
        <!-- 这是页头部分,所有页面共享 -->
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" runat="server" href="~/">应用名称</a>
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li><a runat="server" href="~/">首页</a></li>
                        <li><a runat="server" href="~/About.aspx">lt;/a></li>
                        <li><a runat="server" href="~/Contact.aspx">联系我们</a></li>
                    </ul>
                </div>
            </div>
        </nav>
        <div class="container body-content">
            <!-- 
                这是内容占位符!
                在使用此母版页的页面中,只有这里的部分可以被替换。
            -->
            <asp:ContentPlaceHolder ID="MainContent" runat="server">
            </asp:ContentPlaceHolder>
        </div>
        <!-- 这是页脚部分,所有页面共享 -->
        <footer>
            <div class="container">
                <p>&copy; <%: DateTime.Now.Year %> - 我的 ASP.NET 应用</p>
            </div>
        </footer>
    </form>
</body>
</html>

内容页

页是一个普通的 .aspx 文件,它被“绑定”到一个母版页,内容页不包含 <html>, <head>, <body> 等标签,只包含 <asp:Content> 控件,这些控件会填充母版页中对应的 <asp:ContentPlaceHolder>

创建步骤:

  1. 右键项目 -> 添加 -> 新建项 -> 选择“Web 窗体”。
  2. 在弹出的对话框中,勾选“选择母版页”选项,然后选择你刚才创建的 Site.master
  3. 点击“添加”。

About.aspx 示例代码:

网页的框架 asp.net 怎么实现
(图片来源网络,侵删)
<%@ Page Title="quot; Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="About.aspx.cs" Inherits="MyWebApp.About" %>
<!-- 
    Content 控件的 ContentPlaceHolderID 必须与母版页中 PlaceHolder 的 ID 完全匹配。
    这里的 "MainContent" 就对应 Site.master 中的 <asp:ContentPlaceHolder ID="MainContent" runat="server">。
-->
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%: Title %></h2>
    <h3>关于我们</h3>
    <p>将此内容替换为关于我们页面的说明。</p>
</asp:Content>

优点:

  • 强类型绑定:编译时检查,ContentPlaceHolderID 不匹配会报错。
  • 设计器支持好:在设计视图中可以清晰地看到母版页和内容页的结构。
  • 功能强大:可以方便地在母版页中访问内容页的属性和方法(反之亦然)。

缺点:

  • 耦合度高页和母版页紧密绑定,更换母版页比较麻烦。
  • 文件结构复杂页都有一个对应的 .cs 代码文件和一个 .master 文件,文件数量较多。

ASP.NET MVC (现代方式)

ASP.NET MVC 采用的是布局页 的概念,与母版页类似,但语法更简洁,与视图引擎(如 Razor)结合更紧密。

布局页

布局页也是一个模板,通常位于 Views/Shared/_Layout.cshtml,它使用 Razor 语法来定义可替换的区域。

Views/Shared/_Layout.cshtml 示例代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />@ViewData["Title"] - MyASP.NETCoreApp</title>
    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css"
              asp-fallback-href="~/css/site.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">应用名称</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-area="" asp-controller="Home" asp-action="Index">首页</a></li>
                    <li><a asp-area="" asp-controller="Home" asp-action="About">lt;/a></li>
                    <li><a asp-area="" asp-controller="Home" asp-action="Contact">联系我们</a></li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container body-content">
        <!-- 
            @RenderBody() 是必须的,它表示将具体视图的内容“渲染”到这里。
        -->
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Core 应用</p>
        </footer>
    </div>
    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMxqIChqDr36Lur+ke4Q=">
        </script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha256-dq1wzW5W4fEI05OQ7SnpJsk8eiiEe2QoUy5k8/+GpUo=">
        </script>
        <script src="~/js/site.min.js" asp-append-version="true"></script>
    </environment>
    <!-- 
        可选:用于在特定页面中渲染额外的脚本或样式。
        一个表单验证页面可以在这里引入自己的 JS 文件。
    -->
    @RenderSection("Scripts", required: false)
</body>
</html>

视图

视图文件(如 About.cshtml)通过 Layout 属性指定使用哪个布局页。

Views/Home/About.cshtml 示例代码:

@{
    ViewData["Title"] = "quot;;
}
<h2>@ViewData["Title"]</h2>
<h3>关于我们</h3>
替换为关于我们页面的说明。</p>
@section Scripts {
    <!-- 
        这里定义的 Scripts 会被渲染到 _Layout.cshtml 中 @RenderSection("Scripts") 的位置。
        这是添加页面特定脚本和样式的标准方式。
    -->
    <script>
        alert("这是关于页面的特定脚本!");
    </script>
}

优点:

  • 语法简洁:Razor 语法非常清晰易读。
  • 灵活性高@RenderSection 提供了比 Web Forms 母版页更灵活的扩展点。
  • 关注点分离:MVC 模式天然地将控制器、模型和视图分离,结构更清晰。
  • 现代 Web 开发标准:与前端技术栈(如 Webpack, Vite)结合更容易。

缺点:

  • 学习曲线:对于初学者,MVC 的概念(控制器、路由、模型绑定)比 Web Forms 更复杂。

ASP.NET Core Blazor (新兴方式)

Blazor 是一个用于使用 .NET 构建交互式客户端 Web UI 的框架,它完全颠覆了传统的请求-响应模式,采用组件化的方式来构建整个应用,包括页面框架。

在 Blazor 中,整个应用(包括布局)都是由一个个可复用的组件组成的。

布局组件

布局组件本质上也是一个 Blazor 组件,但它通常包含一个 @Body 占位符。

Shared/MainLayout.razor 示例代码:

@inherits LayoutComponentBase
<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>
    <main>
        <!-- 
            @Body 会在这里渲染当前页面的内容。
            这与 MVC 的 @RenderBody 和 Web Forms 的 ContentPlaceHolder 类似。
        -->
        @Body
    </main>
</div>

页面组件

页面组件(如 About.razor)通过 @layout 指令指定其布局。

Pages/About.razor 示例代码:

@page "/about"
@layout MainLayout
<h3>lt;/h3>
<p>这是一个使用 Blazor 组件化方式构建的关于页面。</p>

优点:

  • 全栈 .NET:前端和后端都可以用 C# 编写,共享代码库。
  • 组件化:UI 被拆分成高度可复用、可维护的组件,构建大型应用非常强大。
  • 现代交互:无需 JavaScript,即可构建复杂的客户端交互。

缺点:

  • 较新技术:生态系统和社区资源相对 MVC 和 Web Forms 较少。
  • 性能考量:对于大型应用,客户端 Blazor 的初始加载包大小可能是一个需要优化的点。

总结与选择

特性 ASP.NET Web Forms (母版页) ASP.NET MVC (布局页) ASP.NET Core Blazor (布局组件)
核心概念 母版页 和 内容页 布局页 (_Layout.cshtml) 和 视图 布局组件 和 页面组件
语法 ASPX/Web Controls Razor Razor
耦合度 较高 中等 低 (纯组件化)
开发模式 事件驱动,类似 WinForms MVC (模型-视图-控制器) 组件化,类似 React/Vue
适用场景 维护旧项目,或需要快速开发企业级内部系统 目前最主流的选择,适合大多数新 Web 应用 构建交互性强的现代单页应用,全栈 .NET 团队
推荐度 不推荐用于新项目 强烈推荐 适合特定场景,非常有前景

如何选择?

  • 如果你要开始一个全新的项目

    • 首选 ASP.NET MVC,它是目前最成熟、社区最活跃、资源最丰富的选择,适合构建绝大多数类型的网站。
    • 如果你的团队是全栈 .NET 开发者,并且希望构建一个交互性非常强的客户端应用(类似桌面应用的体验),Blazor 是一个值得尝试的未来方向。
  • 如果你需要维护一个旧的 ASP.NET Web Forms 项目

    继续使用和优化现有的母版页结构是合理的,如果条件允许,可以考虑逐步将其迁移到 MVC 以获得更好的长期维护性。

希望这个详细的解释能帮助你理解 ASP.NET 中实现网页框架的各种方法!