MVC 与 Ajax - 初学者入门(第 3 部分)






4.81/5 (13投票s)
这是一个关于如何在 MVC 中使用 Ajax 的快速教程,在一个页面中实现所有基本的添加、更新、编辑和删除功能。
引言
正如我所承诺的,本文是本系列第一部分和第二部分中 MVC 的进一步进展。在这里,我们将使用 Ajax/Jquery 来实现我们之前完成的相同功能。
众所周知,Web 的核心在于服务的速度,而最快的客户端服务方式无疑需要 Ajax,因为它会减少数据交换,或者我们可以说只交换必要的数据,从而避免带宽浪费并提供更好的性能。此外,它还为您的应用程序提供了一个更具交互性的界面。那么,让我们开始 MVC + Ajax 吧。
背景
我们将在项目中利用一些新术语/技术来实现 Ajax。当您通读本文时,您将获得关于这些的简要信息。因此,如果您对它们有所了解,那将是很好的。这些是“Bundling
”和“PartialViews
”。
捆绑和压缩:这既不是一个新概念,也不复杂。实际上,它非常简单,我将在本文后面解释。
部分视图:这些是 Razor 视图页面,但它们可以被重用。如果您想在 Web 应用程序中重用一个视图,您可以使用部分视图概念。部分视图就像一个带有文件扩展名“.cshtml
”的常规视图。我们可以在需要为 MVC Web 应用程序重用页眉、页脚的情况下使用部分视图。我们可以说它类似于 ASP.NET 中的用户控件概念。
因此,有了这些非常基础的知识,您就可以继续了。此外,随着文章的进展,您将详细了解它们。
使用代码
在我们开始 MVC 与 Ajax 之前,有几个要点需要考虑。由于 Ajax 与 Jquery 库一起工作,所以必须包含 Jquery 库,并且您会在 Scripts 文件夹中找到一些附加文件(见下图),即“jquery.unobtrusive-ajax.js
”及其压缩版本,它负责 MVC 中使用 Ajax 的所有 Ajax 回发。
所以如果你忘记添加这个文件,你的 Ajax 代码块将不起作用,并将执行正常的 PostBack。
将文件包含在捆绑中
包含此 JavaScript 文件有多种方法,但必须选择不影响性能的最有效方法。到目前为止,所有文件(css 或 js)都从我们的“_Layout.cshtml
”页面中包含,该页面充当主题的母版页。它位于“Views/Shared
”文件夹中。所以打开该页面,您会在底部看到以下几行
在这里,您可以看到我们在此命名空间下添加了文件捆绑(我们可以说这只是逻辑分离)。这里就涉及到了“捆绑和压缩”的作用。
捆绑和小型化
这是一个过程,通过它我们创建在整个应用程序中所需的文件捆绑,并在应用程序加载时注册这些文件,从而避免它们一次又一次地加载。这将避免带宽浪费,缩短加载时间,最终获得更好的性能。
要将文件添加到捆绑包中,我们必须遵循以下步骤
1. 转到应用程序根文件夹中的“App_Start”文件夹。
2. 打开名为“BundleConfig.cs”的文件。此文件包含我们创建的捆绑包的配置
3. 添加新的捆绑包或修改现有的捆绑包。现在,如果您要添加一些具有特殊情况(例如手动验证)的文件,您可以创建新的捆绑包,否则最好将文件添加到最相关的捆绑包。在我们的应用程序中,我们将把“ajax.unobtrusive.ajax.min.js
”文件添加到我们现有的捆绑包中。下面是其快照。
在这里您可以看到我们没有添加完整的文件路径,而是只添加了“jquery.unobtrusive*
”。此功能使应用程序能够避免命名问题,例如在我们的示例中,它将包含名称以“jquery.unobtrusive
”开头的文件。
您还会注意到,“{version}
”一词出现在上面捆绑块的第二行。这用于避免版本问题。如果您有同一文件的两个版本,它将自动包含更高版本的文件。
通过这种方式,我们添加了js
文件或css
或任何我们想要注册的文件。现在我们准备好在我们的第一个 MC 应用程序中使用 Ajax 功能。现在让我们开始在 MVC 中实现 Ajax
预期输出
通过使用 Ajax,我们将创建一个单页应用程序,用户可以在其中
- 添加记录。
- 编辑现有记录。
- 删除现有记录。
所以下面是本文我们将要实现内容的截图
在这里您可以看到,左侧是与系列早期部分中添加的相同的用于查看、编辑或删除已保存记录的网格,右侧是与第一部分或系列中相同的视图。
简而言之,我们将把这两个页面合并成一个,并使用 Ajax 在这些视图之间进行通信,从而在单个页面上实现相同的功能。
添加新控制器
添加一个新控制器。给它一个合适的名称。我把它命名为‘FirstAjaxController’
,这样我们就能很容易地识别出它将在其中实现 Ajax。默认情况下,您会在此控制器中有一个 Index 方法,并在Views/FirstAjax文件夹中有一个该方法的 Index 视图。
现在,正如我上面提到的,我们将把两个页面视图合并到一个页面中,这里出现的问题是,我们针对两种情况有不同类型的视图,即在系列的第一部分中,我们将视图类型转换为“@model StartWithMVC.Models.Employee
”,而在第二部分中,我们已将视图类型转换为(强类型)“@model List<StartWithMVC.Models.Employee>
”。那么,我们如何在单个页面中处理这个问题呢?为此,我们有一些技术。通过使用它们,我们可以实现我们的逻辑。可以选择任何一种技术,但清晰和更好的方法总是首选。要深入了解这些,您可以学习以下文章
‘https://codeproject.org.cn/Articles/687061/Using-Multiple-Models-in-a-View-in-ASP-NET-MVC-M’
在我们的应用程序中,为了解决这个问题,我们将使用“Tuple
”技术。在此技术中,我们将创建一个新类或模型,它可以对多种数据类型进行分组。因此,
- 添加新的模型文件夹并给它一个合适的名称(我把它命名为“
AddUpdateEmployee.cs
”) - 在该类/模型中写入以下代码行
public Employee EmpModel { get; set; } public List<Employee> ListEmpModel { get; set; }
这里第一行包含 Employee Model 对象,第二行包含 List 类型 employee Model 对象。因此,如果我们将视图强类型转换为这个对象,我们就可以将两个模型继承到一个模型中。您将看到我们如何在应用程序中使用此模型。
这是如果遇到任何问题/困惑时,它将如何进行的屏幕截图。
添加/更新索引视图
现在,通过右键单击控制器(FirstAjaxController.cs
)中的 Index 方法,转到“index.cshtml
”。现在在该文件中编写以下代码
@model StartWithMVC.Models.AddUpdateEmployee @{ ViewBag.Title = "Index"; } <h2>Employee</h2> <div id="divListPanel" class="left_panel"> @Html.Partial("_ViewAllRecords", Model.ListEmpModel) </div> <div id="divEditPanel" class="right_panel"> @Html.Partial("_UpdateEmployee", Model.EmpModel) </div>
现在,您可以看到我们在此视图中使用了“AddUpdateEmployee
”元组,并且我们进一步使用此模型来获取所需的 Employee 和 List<Employee> 类型对象。
为什么使用局部视图?
因为 Ajax 在响应中返回完整的页面 HTML,并用整个页面 HTML 更新目标 div,从而导致页面中又打开一个页面。为了避免这种情况,我们只为我们想要在任何特定操作中更新的部分创建局部视图。
1. 局部视图 "_ViewRecord"
@model List<StartWithMVC.Models.Employee> <div class="table_container"> <table> <thead> <th>HR Emp Id</th> <th>Last Name</th> <th>First Name</th> <th>City</th> <td><b>Edit</b></td> <td><b>Delete</b></td> </thead> <tbody> @foreach (var item in Model) { <tr> <td>@item.HREmpId</td> <td>@item.LastName</td> <td>@item.FirstName</td> <td>@item.City</td> <td>@Ajax.ActionLink("Edit", "EditRecord", new { recordID = @item.EmpId }, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divEditPanel" })</td> <td>@Ajax.ActionLink("Delete", "DeleteRecord", new { recordID = @item.EmpId }, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divListPanel" })</td> </tr> } </tbody> </table> </div>
如您所见,这与我们在第2部分视图中使用的完全相同。我们所做的唯一更改如下
如您所见,这里我们使用了 '@Ajax.ActionLink'
而不是 '@Html.ActionLink'
,从而引入了 Ajax。这里我们添加了一个 AjaxOption 属性,它将设置 Ajax 调用的处理方式。在这里,我们告诉 Ajax 我们希望在此 Ajax 调用中替换 'divEditPanel' 的内容。
同样,在删除链接上,我们告诉 Ajax 我们希望更新“divListPanel
”,即左侧面板的内容。
2.局部视图"_UpdateEmployee"
@model StartWithMVC.Models.Employee @using (Ajax.BeginForm("SaveEmployee", "FirstAjax", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divListPanel", OnComplete="resetFields();" })) { <fieldset> @Html.HiddenFor(m => m.EmpId) <p> @Html.LabelFor(m => m.HREmpId) @Html.TextBoxFor(m => m.HREmpId, new { maxlength = 10 }) </p> <p> @Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName, new { maxlength = 30 }) </p> <p> @Html.LabelFor(m => m.LastName) @Html.TextBoxFor(m => m.LastName, new { maxlength = 30 }) </p> <p> @Html.LabelFor(m => m.Address) @Html.TextBoxFor(m => m.Address, new { maxlength = 30 }) </p> <p> @Html.LabelFor(m => m.City) @Html.TextBoxFor(m => m.City, new { maxlength = 30 }) </p> </fieldset> <input type="submit" name="btnSave" value="Submit" /> }
这里我们也使用了与之前(第一部分)相似的代码,但我们所做的唯一改变是通过使其成为 Ajax 提交表单,将 Ajax 引入了表单。
因此,这将通过点击执行 Ajax 请求,并调用“resetFields()
”JavaScript 函数来清除右侧区域的字段。下面是 JavaScript 函数
<script type="text/javascript"> function resetFields() { $('input[type=text]').val(''); } </script>
这就是所有视图方面的内容,现在我们将看看控制器中的变化。
控制器动作代码块
1. 索引动作
在控制器中的 index 方法中写入以下几行。
StartWithMVCEntities db = new StartWithMVCEntities(); var tempModel = new AddUpdateEmployee(); tempModel.EmpModel = new Employee(); tempModel.ListEmpModel = db.Employees.ToList(); return View(tempModel);
如您所见,我在这里使用了tempModel tuple
模型,并分配了一个 Employee 模型对象和 List <Employee>
对象,然后将其传递给视图。现在检查上面 'Index.cshtml
' 视图代码,我们在那里使用了它。因此,我们可以通过多个模型来服务一个视图。
2. 保存/更新员工操作
写入以下代码以保存员工。您会注意到此方法与文章系列第二部分中编写的方法有一些变化。
public ActionResult SaveEmployee(Employee objEmployee) { StartWithMVCEntities db = new StartWithMVCEntities(); if (objEmployee != null && objEmployee.EmpId != 0) { //TODO : your entity framework code for updateing the employee details //fetch object for the editted employee record Employee objEmp = db.Employees.ToList().Find(m => m.EmpId == objEmployee.EmpId); //Assign the edited value to getch object objEmp.HREmpId = objEmployee.HREmpId; objEmp.FirstName = objEmployee.FirstName; objEmp.LastName = objEmployee.LastName; objEmp.Address = objEmployee.Address; objEmp.City = objEmployee.City; //finally save the chagne to database db.SaveChanges(); //this line will reset the default model state or properties ModelState.Clear(); List<Employee> listEmpModel = db.Employees.ToList(); return PartialView("_ViewAllRecords", listEmpModel); } else { //TODO : your entity framework code for saving the employee details db.Employees.AddObject(objEmployee); db.SaveChanges(); //this line will reset the default model state or properties ModelState.Clear(); List<Employee> listEmpModel = db.Employees.ToList(); return PartialView("_ViewAllRecords", listEmpModel); } }
注意事项
现在很清楚,如果保存或更新任何员工,那么它应该在左侧的视图记录列表中显示/反映更改。因此,我们只需要更新该部分,并在完成后重置字段。为此,以下几行非常重要
ModelState.Clear(); 和 return PartialView("_ViewAllRecords", listEmpModel);
modelstate.clear():这将重置模型状态,并在保存和更新时重新初始化表单,从而使保存和更新操作保持独立。因此,在添加的情况下,我们用于保存函数比较的主键值将为零,而在更新情况下,它将为非零。
在 'return PartialView("_ViewAllRecords", listEmpModel);
' 行中,我返回了由该局部视图生成的视图,同时我还传递了该局部视图所需的列表模型。
因此,我们得到了所需的输出,而无需完全加载页面,并且只更新了所需的部分/区域,从而提高了性能。
现在要重置字段,我调用了上面编写的 JavaScript 函数。这非常简单。
3. 编辑记录(使记录可编辑)
现在,当我们在视图记录网格中单击“编辑”链接时,需要将值显示在字段中,因此很明显我们需要更新右侧部分,或者我们可以说“_UpdateEmployee
”视图。下面是具有类似更改的代码。
public ActionResult EditRecord(int recordID) { //TODO : your entity framework code for showing the employee details StartWithMVCEntities db = new StartWithMVCEntities(); Employee objEmp = db.Employees.ToList().Find(m => m.EmpId == recordID); return PartialView("_UpdateEmployee", objEmp); }
4. 删除记录
现在,当我们从网格中删除记录时,我们只需要更新左侧部分,或者说只更新“_ViewRecords
”视图,我们也将这样做。下面是相应的代码
public ActionResult DeleteRecord(int recordID) { //TODO : your entity framework code for showing the employee details StartWithMVCEntities db = new StartWithMVCEntities(); Employee objEmp = db.Employees.ToList().Find(m => m.EmpId == recordID); db.Employees.DeleteObject(objEmp); db.SaveChanges(); List<Employee> listEmpModel = db.Employees.ToList(); return PartialView("_ViewAllRecords", listEmpModel); }
运行项目
现在我们已经准备好运行应用程序了。您会看到与我开头提到的相似的视图。因此,我们已经实现了我们的目标。
注意:您的视图可能与我提供的图片有一些设计上的差异,这仅是由于某些 CSS“样式表”造成的。那不是我们讨论的一部分,所以我没有包含它。如果您希望拥有它,请下载上面附件中的源代码。
关注点
因此,我们刚刚看到了如何将 Ajax 与 MVC 结合使用,以在同一页面上实现所有添加、更新和删除记录,同时最大限度地减少服务器负载。现在,正如前面提到的,感兴趣的要点是
- 部分视图
- 捆绑和小型化
- Ajax Js 文件