使用 ASP.NET MVC 创建桌面用户体验 (第 1 部分,共 3 部分)
第 1 部分:掌握 ASP.NET MVC 项目模板和技术(Razor、jQuery、JavaScript、Bootstrap、CSS)。第 2 部分:构建一个在浏览器中运行但感觉像使用桌面应用程序的 ASP.NET MVC 应用程序。
引言
随着应用程序逐渐转向在浏览器中运行,用户失去了一些桌面提供的直观功能。在这里,我特别想到 Windows Forms 作为用户与之交互的对象,以及提供右键单击元素以了解有关该项目可用选项的上下文菜单。
以下动画 GIF 提供了我们正在努力实现的目标。(此基本用户体验功能在本系列第 2 部分结束时完成 -- 使用 ASP.NET MVC 创建桌面用户体验 (第 2 部分,共 3 部分)[^])。
文章分为两三部分:工作原理
我将这篇文章分为两三部分,以便您专注于开发的每个部分。
第 1 部分:从零开始创建 MVC 应用程序的初学者指南
我们从 Visual Studio ASP.NET MVC 空模板开始,只添加我们需要的东西。
您将单独了解我们添加的每个部分,并了解为什么涉及如此多的不同技术,以及 ASP.NET MVC 如何将它们整合在一起。由于移动部件的数量,ASP.NET MVC 可能会让人不知所措。
本文的第 1 部分将引导您了解为什么 ASP.NET MVC 中包含这些内容,同时探索底层的 MVC 应用程序框架。
第 1 部分:深入了解 ASP.NET MVC 工作原理
我们将创建我们的应用程序基础,同时深入探讨我们添加每个部分的原因。
到您完成本文时,您将掌握以下知识:
- 我应该选择哪个 MVC 模板和哪些选项?
- 了解 MVC 项目结构 - 所有这些文件夹是什么以及每个文件夹中应该放什么
- 当我创建一个空项目、构建并运行时会发生什么?一个错误,但它意味着什么?
- 为什么我需要先将一个
Controller
添加到项目中? - 基本上,什么是
Controller
? - 如何轻松添加关联的视图?
- 什么是
_ViewStart
以及我是否应该使用它? - 所有这些模板 HTML 是从哪里来的?
- 什么是
_Layout.cshtml
以及它与Layout
应用程序变量有什么关系? - MVC 路由是什么以及它们是如何工作的?
- 我的 HTML 中那些奇怪的
@{ }
是什么,它们究竟做了什么?Razor 视图引擎指令 - 为什么我的 HTML 中有时只看到
@Things
而没有括号? - 基本的 MVC 应用程序从哪里获取其样式?CSS 在哪里以及如何更改它?(Bootstrap)
- MVC 自动包含哪些 JavaScript 库以及如何使用它们?(Bootstrap、jQuery、Modernizr)
- Bootstrap.JS 和 Bootstrap.CSS?是的,同一枚硬币的两个不同面
- 我应该将我的 JavaScript 放在哪里以及如何在 MVC 上下文中正确加载我的 JS 文件?
- JavaScript IIFE(立即调用函数表达式)
- HTML 加载后运行脚本 - jQuery
ready()
方法
如果您已经构建了 ASP.NET MVC 应用程序并且了解它们的工作原理,请随意跳过第 1 部分。
第 2 部分:构建可重用的上下文菜单应用程序
第 2 部分将深入探讨创建可重用 ASP.NET MVC 应用程序所需的特定代码,该应用程序可创建桌面用户体验 (UX)。您将看到创建类似于 Windows Form 对象(实现上下文菜单,其功能与桌面应用程序中完全相同)所需的 JavaScript、jQuery、Bootstrap、Razor、CSS 和 C# 代码。我同意完成这项工作需要很多不同的技术,但我们将尽可能地隔离我们在每种技术上的工作,以便您对每种技术都有深入的理解。在文章结束时,您将理解添加到项目中的每一行代码。
第 3 部分:构建客户端/服务器交互
在第三部分中,我们将构建完成应用程序功能的代码,同时学习上下文菜单如何触发 AJAX 调用到服务器。我们还将学习如何使用控制器接收请求并构建部分视图,这些视图将作为单独的窗口呈现在我的 SPA(单页应用程序)上。
背景
一年多以前,我使用 ASP.NET MVC 创建了一个原型应用程序。这是一个简单的应用程序,旨在允许用户查询数据并查看结果。然而,我希望使应用程序对桌面用户尽可能直观,最终我设计出了一个具有桌面应用程序外观和感觉的东西。由于它是一个原型,我希望重新审视它,清理代码并使其更具可重用性。希望您会发现这是对 ASP.NET MVC 的一个有趣的入门。我相信您会发现您可以重用和自定义此代码以用于您自己的应用程序。
第 1 部分:步骤和主题概述
以下是我们将要经历的所有步骤,以便对 ASP.NET MVC 应用程序的工作原理有一个深入的理解。
- 创建一个空白 ASP.NET MVC 项目
- 添加一个新的主控制器 -- 允许它添加默认操作。
- 右键单击 Index() 操作的视图并添加一个新的视图
- 将新的 javascript 文件添加到 Scripts 目录,命名为 contextMenu.js
- 检查 Site.css 以及样式的来源。
现在,我将引导您完成所有这些步骤,并包含屏幕截图,以便您准确了解在 Visual Studio 中完成这项工作的样子。我将使用 Visual Studio 2013,但在 2015 年也会非常相似。
创建空白 MVC 项目
启动 Visual Studio 并创建一个新项目。
从树状视图侧选择 Visual C#...Web...,然后选择ASP.NET Web 应用程序,如图像所示,然后单击 [OK] 按钮。
将出现一个新对话框,在这里您需要使其与下图中所示完全匹配。
您需要选择空白项目,但也要“添加 MVC 和 WebAPI 的文件夹和核心引用”。
如果您愿意,当然也可以添加单元测试,但为了使文章更短,本文中我不会这样做。
确保所有其他设置与前一个屏幕截图所示完全相同,然后单击 [OK] 按钮。
执行此操作后,Visual Studio 将根据您所做的模板选择创建新项目。
Visual Studio 应在解决方案资源管理器中显示项目文件夹和文件。即使这是一个“空项目”,它仍然包含相当多的内容(文件夹、global.asax、web.config 等)。
构建空解决方案
如果您构建空解决方案,它将成功。但是,运行应用程序将失败。现在让我们尝试一下,以便您了解我们在下一步中要做什么。当您构建并运行后,您将在网页浏览器中看到以下内容:
出现这种情况是因为用户尝试访问的路由 (/) 没有处理程序 (Controller)。换句话说,我们的 MVC 应用程序没有任何东西可以用来为用户生成 HTML 输出,因此它返回 404 错误(未找到资源)。
在App_Start
文件夹中的RouteConfig.cs
文件中可以找到解决此问题的一些线索。该文件有一个 RegisterRoutes 方法,用于设置应用程序中有效的默认路径。
RegisterRoutes 方法如下所示:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
加粗的行创建默认路由。默认路由查找名为Home
的控制器,其中包含名为Index
的Action
(方法)。
按照约定,MVC 应用程序期望路由找到一个控制器——在本例中是主控制器。当然,我们的应用程序中还没有包含任何控制器。让我们添加第一个。
添加新控制器
右键单击“Controllers”文件夹,然后从出现的上下文菜单中选择“添加”=>“控制器...”,如图所示。
将出现一个包含很多选项的大对话框。我们想要一个相对简单的控制器,但我不想让它完全为空,所以我会让 Visual Studio 模板创建一些基本的读写操作。继续选择显示的第二个选项,然后单击 [添加] 按钮。注意:我裁剪了一些这些窗口,因为它们太大。
当您点击 [添加] 按钮时,另一个对话框会弹出,要求您命名控制器。
ASP.NET MVC 约定
ASP.NET MVC 使用约定优于配置。这仅仅意味着它遵循一些基本的流程模式,因此您不必配置所有内容。然而,这意味着您需要学习流程模式。在这种情况下,Visual Studio 试图通过突出显示您应该重命名的控制器名称部分来帮助您。
Visual Studio 约定:控制器和视图
在 ASP.NET MVC 中,约定是控制器命名为<name>
Controller,视图命名为<name>
View,其中<name>是开发者提供的值。此外,控制器及其匹配视图的<name>
也将相同。
HomeController 将拥有 HomeView
因此,我们将我们的第一个控制器命名为 HomeController,稍后您将看到一个名为 HomeView 的视图将被添加。继续更改名称并单击 [添加] 按钮。
当您添加新控制器时,Visual Studio 将生成并显示 HomeController.cs 文件。
您可以在解决方案资源管理器中看到 Visual Studio 已将新文件 (HomeController.cs) 添加到 Controllers 文件夹。另请注意,编辑器中的 View() 方法当前显示为红色文本。这是因为它们尚未在任何地方实现。我们稍后将通过添加视图来解决这个问题,但首先让我们看看如果现在构建并运行会发生什么。
不带视图的构建和运行
继续构建并运行项目。当您这样做时,您将看到以下内容:
熟悉错误消息
起初你可能会认为那只是一堆废话。然而,了解 MVC 应用程序在发生这种情况时试图告诉你什么很重要。这很重要,因为如果你要花任何时间开发 MVC 应用程序,你迟早会遇到这个错误消息。这是因为如果你的 MVC 应用程序正常工作,但视图被意外删除或未迁移,你就会看到这个错误。
什么是匹配视图?
如您所见,MVC 框架正试图警告您,它在某些地方(按照约定查找的地方)搜索了一个视图,但没有找到匹配的视图。
框架试图查找的视图的线索在顶部的错误消息中:
MVC 框架视图“Index”或...
这表明控制器正在搜索名为Index
的匹配视图,但找不到它。
这是因为我们还没有添加与 HomeController 匹配的有效视图。同样,这都与 MVC 应用程序启动时运行的RegisterRoutes
方法中的默认路由有关。
现在,让我们添加一个新视图来解决这个问题。
添加视图
Visual Studio 在添加视图方面非常有用。在打开 HomeController 的编辑器中,您可以在 Index() 方法内部或 Index() 方法的第一行上右键单击,然后会出现一个上下文菜单。
当菜单出现时,选择 [添加视图...] 菜单项。
当您进行该选择时,将出现“添加视图”对话框。
Index 是我们视图的正确名称,所以我们将接受它和所有默认值,通过点击 [添加] 按钮。然而,在我们这样做之前,请注意 [使用布局页] 复选框被选中,即使没有选择布局。这表示我们想要一个默认布局,我们将在本文的后续部分中看到更多相关内容。
现在点击 [添加] 按钮,Visual Studio 将为我们创建几个文件。
一旦 Visual Studio 完成文件生成,它将在编辑器中打开Index.cshtml
文件。
视图文件很小(只包含四行代码),但我们现在可以成功运行应用程序。
Index.cshtml 的所有代码
以下是编辑器中显示的完整代码列表
构建并运行:基本视图
继续构建并再次运行,您现在将在网页浏览器中看到一个非常基本的页面。
尽管网页如此基础,但它仍然像魔术一样,因为很难确定创建输出的 HTML 是从哪里来的。
基本的 HTML 结构在哪里?
首先,您知道有效的 HTML 文档需要的基本 HTML 结构、HTML、HEAD、BODY 和其他标签在哪里?
布局和 ViewStart 魔法
还记得我们创建视图时,在“创建视图”对话框中接受了那个额外的名为 [使用布局页
] 的复选框吗?除了Index.cshtml
文件之外,该选择实际上为我们创建了另外两个文件。您可以在解决方案资源管理器中“Views”文件夹下更清楚地看到它们。
您可以看到,我们现在在 Views 文件夹下有两个新文件夹(Home 和 Shared),并且创建了三个新文件
- Home\Index.cshtml
- Shared\_Layout.cshtml
- _ViewStart.cshtml
_ViewStart.cshtml
这是一个特殊文件,MVC 框架在应用程序启动时会查找它。如果找到,应用程序将遵循其指令加载其他文件。当然,如果找不到也没关系。我们的 _ViewStart.cshtml 内容很少,但它确实为我们提供了另一个关于所有 HTML 可能在哪里找到的线索。它指向了我们创建初始视图时由 Visual Studio 生成的另一个文件。
您可以在我发表在 CP 上的另一篇文章中了解 _ViewStart.cshtml 如何被 RazorViewEngine 加载的详细信息:Razor:MVC 视图引擎的秘密揭示[^]
_Layout.cshtml
_Layout.cshtml 是一个模板 HTML 文件,它将在全网站范围内使用(这就是为什么它在 Shared 目录中)。
检查这个文件更有价值,因为我们最终找到了我们知道有效 HTML 所需的 HTML 标签。此时,这个文件代表了我们网站的基本结构。然而,整个文件只有 40 行。
** 这是我们希望将任何希望显示在我们所有页面上的 HTML 放置的地方。**
注意:这是放置表示我们上下文菜单的 HTML 的理想位置,因为我们希望它在应用程序的任何地方都可以使用。
由于我们将使用此文件,因此快速查看整个文件。
关于 _ViewStart.cshtml 的更多信息
我们将更多地讨论 _Layout.cshtml 中发生的事情,但首先让我们讨论组成整个 _ViewStart.cshtml 文件的三行奇怪的代码。
Razor 视图引擎指令
_ViewStart.cshtml 中的代码是一个 Razor 视图引擎指令。它是 MVC 框架知道将被 Razor 视图引擎消耗的专用模板代码。我们编写这样的代码是为了引起 Razor 视图引擎的注意。该指令在我们的 HTML 文件中(命名为 cshtml,表示它可以包含 Razor 视图引擎可以消耗的 C# 代码)。
Razor 视图引擎编译代码
当 MVC 框架看到特殊字符@{ }
时,它知道这是 Razor 视图引擎介入的信号。一旦它识别出指令,它就明白其中的代码将是 C# 代码。
网页浏览器无法编译或运行 C#
显然,网页浏览器不会编译或运行 C# 代码。但是,网页浏览器永远不会看到这些代码。相反,Razor 视图引擎会编译代码并遵循指令在服务器端运行 C# 代码。
在我们的基本 _ViewStart.cshtml 中,只有一行代码。
Layout = "~/Views/Shared/_Layout.cshtml";
那行代码将一个名为 Layout 的应用程序全局变量设置为一个字符串,该字符串表示将在您的 ASP.NET MVC Web 应用程序中显示的所有页面上使用的 HTML 结构。
内置 ASP.NET MVC 变量
Layout
是 ASP.NET MVC 应用程序为您创建的一个内置 ASP.NET MVC 变量。这就是为什么它感觉像魔术一样,仿佛变量凭空出现。它是您的 Web 应用程序运行所在的应用程序框架的一部分。
仅使用 @ 符号的内联代码
正如我之前所说,特殊字符@{ }
表示中间的行将是 C# 代码。但是,如果您想运行单行代码或获取变量的值,只需在其前面加上@
符号即可。
在 _Layout.cshtml 文件的 head 部分有一个很好的例子。您可以看到一行代码如下所示:
<title>@ViewBag.Title - My ASP.NET Application</title>
这里重要的部分是@ViewBag.Title
,它是一个 Razor 视图引擎指令,表示它应该获取@ViewBag
变量(一个动态集合对象)的值,并找到名为Title
的属性,检索其值并在此精确位置渲染它。这使得我们的页面标题成为该属性中的任何字符串,再加上其余的正常字符(- 我的 ASP.NET 应用程序)。
你可能想知道,“@ViewBag.Title
在哪里设置的?” 回头看看你的 Index.cshtml 文件的顶部,你会看到一个 Razor 视图引擎指令块,它看起来像:
@{
ViewBag.Title = "Index";
}
这就是值设置的地方。这意味着当您的 Index.cshtml 文件渲染时,它会将页面标题文本设置为:Index - 我的 ASP.NET 应用程序
这个小节确实揭示了 ASP.NET MVC 内部工作的许多知识。但是,等等,还有更多。:)
我们可以强制 Visual Studio 的 Intellisense 在正确的位置输入代码,从而向我们展示更多这些 ASP.NET MVC 变量。
强制 Visual Studio Intellisense
在 Visual Studio 编辑器中打开您的 Index.cshtml 文件。移动到指令块下方,这样您就不在括号内,然后输入
<p>
此时,编辑器应该为您填写结束标签</p>
,并且您的光标将在标签之间。这只会帮助我们运行代码。现在输入一个@
符号,Intellisense 将弹出。
注意:后来我注意到这个智能感知实际上是由我的 Resharper 实例创建的。仅仅使用 Visual Studio 并不会完全显示出来,这很不幸。
您看到最后一项了吗?它是应用程序的全局Layout
变量。这不是很酷吗?我们正在揭示大量可以通过 Razor 指令使用的对象和变量。
让我们添加一些并运行 Web 应用程序,看看会显示什么。
我修改了我的 Index.cshtml 文件,使其看起来像以下内容:
@{
ViewBag.Title = "Index";
}
<p>@Layout</p>
<p>@App</p>
<p>@IsAjax</p>
<p>@IsPost</p>
<h2>Index</h2>
同样,我将它们放在
标签之间,这样我们就会有换行符。当你运行它时,你会得到类似以下的内容:
显示的第一行代表我们在 _ViewStart.cshtml 文件中最初看到的字符串。第二行是表示应用程序对象的类的名称。第三行是 false,因为这不是一个 Ajax 请求。最后一行是 false,因为页面是通过 HTTP Get 而不是 Post 检索的。
这些知识将极大地帮助您的 MVC 应用程序开发。现在,让我们看看如何使用应用程序框架的其他元素来创建我们的自定义应用程序。
JavaScript 和 CSS
现在您已经了解了 ASP.NET MVC 框架底层发生的大部分事情,您已准备好学习如何开始添加自己的自定义 JavaScript 以及如何在应用程序中更改 CSS 样式。之后,您将准备好跳到本文的第 2 部分。
默认库
默认情况下,MVC 项目模板会向我们的项目添加一些 JavaScript 库。要查看所有包含的库,请查看解决方案资源管理器并打开Scripts
文件夹。
了解压缩 JavaScript
首先要理解的是,目录中存在重复的 JS 文件。这是因为,例如,bootstrap.js 和 bootstrap.min.js 文件实际上是同一个文件,只是名称中包含“min”的文件是压缩版本。这仅仅意味着它经过了一个过程,该过程剥离了多余的空格,并在某些情况下重命名了变量,使其更短。这使得生成的 JS 文件更小,并提供两个好处:
- 更快的传输
- 混淆代码(略微保密)
明显的问题是当您必须因错误而逐步执行任何 JavaScript 时。在这些情况下,您不想查看压缩版本。以下是常规 bootstrap.js 与 bootstrap.min.js 的比较示例。常规版本在红线的左侧,压缩版本在右侧。
这意味着实际上我们项目中只有三种不同的 JavaScript 库
- jQuery
- Bootstrap
- Modernizr
在这个项目中,我们只直接使用 jQuery 库(从我们的 JavaScript 调用 jQuery 方法)。Bootstrap.js
与Bootstrap.css
文件一起在某些地方使用,但在大多数情况下,我们也不需要利用 Bootstrap 功能。
Bootstrap JS 和 Bootstrap CSS:两种不同的东西
很容易将 Bootstrap JavaScript 与 Bootstrap CSS 样式混淆,但它们实际上是两回事。Bootstrap 开发人员只是注意到有些事情只能通过 JavaScript 来完成,因此他们为这些事情添加了一个帮助文件。
当然,我们将间接使用Bootstrap.css
样式,但我们将在本文后面讨论这一点。
JavaScript 库在哪里加载?
要了解库实际上是在哪里加载供我们使用的,我们需要再次查看_Layout.cshtml
文件。我们现在明白,此文件将为我们应用程序中的每个页面加载(因为_ViewStart.cshtml
将全局应用程序变量Layout
设置为指向它)。
库实际加载的位置有两个。
加载 JavaScript:它在 HTML 中的位置
通常,JavaScript 在任何网页上有两个加载位置(这不仅限于 ASP.NET MVC,而是基本上所有网页)
- HTML 网页顶部:通常在
<head>
标签内 - HTML 网页底部:通常是结束
</body>
标签之前的最后一个项目
原因如下:
- 从
<head>
标签加载基本上是 HTML 早期以及网页如何加载的遗留物。将 JavaScript 放在<head>
标签中是为了确保 JavaScript 在页面渲染时加载并准备就绪。这样,函数和值就可以从 HTML DOM 元素中获取。 - 页面底部(紧靠
</body>
标签之前)现在使用得更频繁,因为页面 onLoad() 方法通常是页面加载完成的信号,现在 JavaScript 代码可以运行,因为所有 HTML DOM 元素都将可用。
IIFE,jQuery Ready 等
现在有许多方法可以处理这种加载顺序问题,例如使用 jQuery.Ready 方法,它在文档加载完成后触发,所以大部分都已经无关紧要了。您仍然应该了解它的工作原理。这也可以通过 IIFE(立即调用函数执行)方法解决,这就是您将在我们的代码中看到的内容。
您将看到_Layout.cshtml
文件中使用了这两个位置。
让我们添加新的 JavaScript 文件,并在页面加载完成后让它做一些事情,以便我们可以确保我们的应用程序框架按预期工作。
添加我们的新 JavaScript 文件
Visual Studio 使这变得非常容易。由于我们将在与其他人相同的文件夹中添加 JavaScript 文件,因此只需右键单击解决方案资源管理器中的 JavaScript 文件夹,然后选择“添加”=>“JavaScript 文件...”菜单项。
将出现一个对话框,您在其中输入 JavaScript 文件的名称并按 [确定] 按钮。您不必包含文件扩展名,因为它知道它是一个 .js 文件。您只需提供基本名称。在我们的例子中,我们将其命名为 ContextMenu。
当您单击 [确定] 按钮时,Visual Studio 将在 Scripts 目录中创建文件并在编辑器中打开该文件。
第一个测试代码片段
我们首先需要做的是将以下代码添加到 ContextMenu.js 中。
//ContextMenu.js
$(function () {
alert("ContextMenu.js is loaded!");
});
JavaScript 注释
第一行显然只是一个 JavaScript 注释。JavaScript 文件中以两个斜杠字符开头的任何行都被视为注释。实际上,任何一行中找到两个斜杠,该行的其余部分都被视为注释并将被忽略。我喜欢添加 JS 文件名,因为当您在文本编辑器中打开文件时(我们经常在编辑 JavaScript 时这样做),您可以快速查看您正在处理的文件。
jQuery ready() 方法
接下来的三行构成了对 jQuery 方法 ready() 的调用,它是一个辅助函数。它看起来非常像 JavaScript IIFE(立即调用函数表达式)。如果你从未见过它,它是一种奇特的语法。但是,如果你把它分解开来,你就能理解它。
现在让我们这样做来展示我的意思。这是重写后的代码
//ContextMenu.js
$(Initialize);
function Initialize() {
alert("ContextMenu.js is loaded!");
}
现在您可以看到我们有一个名为 Initialize() 的命名函数。我们仍然有那个以$(
开头的奇怪的第一部分。那实际上是 jQuery 的缩写语法,它代表一个名为$()
的方法。
该方法是 jQuery 的$.ready()
方法,但我们将其缩写为$()
。该方法仅在整个 HTML DOM(文档对象模型——所有 HTML 元素)加载完成后才会运行。这使我们能够知道页面何时完全加载,以便我们可以在需要时对 HTML 元素进行操作。
在我们的案例中,我们希望
- 页面加载 - 我们在
$()
方法中得到通知。 - 我们的初始化代码运行
我已经将 Initialize 函数拆分到它自己的命名部分以使其清晰,但正如您在原始代码清单中可以看到的,我不需要这样做。
$() 方法接受一个参数
$()
方法接受一个参数。该参数可以是以下两种情况之一:
- 一个函数名 - 这是我们在第二个例子中使用的
- 一个匿名函数 - 这是我们在第一个例子中使用的
匿名函数不包含名称,并具有以下形式
function () {
// function body
}
我们最初的匿名函数是
function () {
alert("ContextMenu.js is loaded!");
}
当该函数运行时,它将简单地显示一个弹出对话框。要让它在页面加载时运行,我们将其添加到$()
方法中。
为此,我们只需用$()
方法调用包装该匿名函数。
再看一遍,现在你可能就都明白了。
$(
function () {
alert("ContextMenu.js is loaded!");
}
);
工作原理如下
当页面加载时,jQuery 方法$()
将自动被调用。当$()
方法被调用时,它将运行匿名方法,其中包含显示弹出对话框(alert)的一行代码。
现在我们有了代码,我们只需要在我们想要使用它的地方添加一个对脚本的引用。
我们在哪里添加脚本引用?
我们将在本文第 2 部分中完成的工作将与Home/Index.cshtml
文件配合使用。
既然这是我们要处理的文件,您可能会认为我们只需要在该文件中添加一个<script>
标签,一切就都连接起来了。
学习并理解你所能的一切
让我们试一下,看看会发生什么,以彻底弄清楚这一点。这也会让我们更好地理解 JavaScript 文件的加载。了解所有这些细节才是成为一名优秀 Web 开发人员的关键。
打开您的 Index.cshtml 文件,并在底部添加以下 HTML 行:
<script src="~/Scripts/ContextMenu.js"></script>
关于波浪号 (~) 呢?
首先,波浪号字符只是告诉 ASP.NET MVC 从应用程序根目录开始搜索文件,然后遵循路径的一种方式。
继续再次运行您的应用程序。
当您这样做时,您会期望alert
对话框出现,但它不会。
保持网页打开,现在让我们看看浏览器中的源代码。
大多数浏览器都允许您通过右键单击页面上的任意位置并从上下文菜单中选择查看页面源代码...来执行此操作。我正在使用 Chrome。
一旦您选择了它,您将看到我们的 C# MVC Web 应用程序创建并发送到浏览器的实际 HTML。
仔细查看列表中的第 36 行,您会看到我们的 ContextMenu.js 在该点加载。
我们的代码没有触发的微妙原因是与 jQuery 库实际加载的位置有关。您在第 43 行的下方看到它了吗?
尝试在库加载前使用库方法
这意味着我们尝试在加载整个 jQuery 库之前访问 jQuery 方法($()
方法)。如果您打开网页浏览器的控制台窗口,其中显示错误,则可以进一步证明这一点。注意:这在 Chrome 中有效,可能在其他浏览器中也有效,但我只在 Chrome 中测试过,因为我在这篇文章上花费了大量时间。
在 Chrome 和许多其他浏览器中,您可以按 F12 键打开控制台窗口。当我这样做时,我看到以下内容:
错误告诉我们 $ 未定义。这是一个非常好的线索,因为未定义的是 jQuery 变量。它甚至告诉我们错误发生在 ContextMenu.js 的第 3 行,这非常有帮助。如果您在 Chrome 中单击它,它会将您带到 ContextMenu.js 中包含 $( 的代码行。
我们如何解决这个问题?
解决这个问题非常容易,因为我们对_Layout.cshtml
了如指掌。该文件加载了我们目前拥有的所有内容,并且它负责加载 jQuery 库。再次查看_Layout.cshtml
并转到底部,您将看到底部附近对 jQuery 库的引用。
让我们从 Index.cshtml 中删除<script>
行,并将其移动到_Layout.cshtml
,放在 jQuery<script>
标签之后。_Layout.cshtml 文件现在看起来如下所示:(我已高亮显示我们添加的行。)
一旦您进行更改。再次构建并运行,您将在页面加载时看到alert
对话框出现。
这里还有一些有趣的事情。请注意,加载事件在浏览器渲染页面之前就已经完成。由于这是真的,页面甚至还没有在后台渲染,看起来好像没有内容。一旦您单击alert
对话框上的确定按钮,您就会看到内容在浏览器中渲染。
还有一件小事要告诉您,以便您了解 CSS 样式的来源。
ASP.NET MVC 中的 CSS 样式从何而来?
这个 ASP.NET Web 应用程序目前还没有多少内容,但在某个地方,我们确实获得了一些轻微的样式,再次感觉像魔法一样。这种轻微的样式出现在应用程序顶部,网页显示“应用程序名称”。它看起来有点像导航栏,当您将鼠标悬停在“应用程序名称”文本上时,文本颜色会从烟灰色变为亮白色。
同样,那个导航栏是在我们的_Layout.cshtml
文件中定义的。这意味着它将出现在我们添加到应用程序的每个View
的顶部。
NavBar 的 HTML 源是一个位于<body>
内容内部的 HTML<div>
标签。
<div 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>
@Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
</ul>
</div>
</div>
</div>
如您所见,div 上设置了一个 CSS 类:navbar navbar-inverse navbar-fixed-top
这些样式是在Bootstrap.css
中定义的,该文件已链接到_Layout.cshtml的顶部。
CSS 样式和内容文件夹
还有一些由 Visual Studio 模板创建的 CSS 样式存储在Site.css
文件中。所有这些文件都可以在解决方案资源管理器中的Content
文件夹中看到。Site.css
是我们将在本系列文章的第 2 部分中添加自定义样式以创建 ContextMenu UI 的位置。
又一个 Razor 视图引擎命令
让我们再看一个 Razor 引擎视图命令,因为它就在这里。您可能在前面的列表中看到了以下代码行:
@Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
希望您现在已经习惯了,每当您在 .CSHTML 文件中看到@
符号时,您会立即想到:“嘿,Razor 在这里做了一些事情,这是 C# 代码。”
这是一个 Html Helper 对象 (@Html
),它正在调用一个名为ActionLink()
的方法。ActionLink
方法接受五个参数,可能还有其他重载。第一个参数是用户将看到的链接文本。第二个参数是处理链接的Controller
,第三个参数是Controller
内部将被调用的Action
。因此,单击该链接将调用我们的Index.cshtml
页面。它相当于 ASP.NET MVC 的主页。
基础已打好:您已准备就绪
我们的理解和结构已经就位,凭借您从本文中获得的知识,您已准备好构建一个真正可用的 ASP.NET MVC 应用程序。
如果您一直跟随,您将对 ASP.NET MVC 应用程序的结构和工作原理有更深入的理解,这将在您持续的 Web 开发中为您提供帮助。感谢阅读我的文章。
代码下载
代码下载只是我们目前创建的简单项目,包含新的 JavaScript 文件 (ContextMenu.js)。第一次构建应用程序时,将通过 Nuget 包管理器检索 MVC 程序集。
历史
2017 年 3 月 22 日 - 第 1 部分首次发布 - 包含基本模板项目。