具有动态内容的 jQuery 模态对话框






4.92/5 (25投票s)
实现一个可以包含真正动态内容的 jQuery 对话框窗口(模态或普通)。
引言
弹出对话框窗口在 Web 开发中非常常见,尤其是在父子 UI 设置中。大多数情况下,它可能包含大部分静态内容,而其中的动态元素只有一些文本更改。但在某些用例中,jQuery 对话框窗口需要根据父页面中选择的某些条件打开非常动态的内容(包括渲染的元素)。
在本文的第一部分,我将演示如何实现一个 jQuery 对话框窗口(模态或普通),该窗口可以包含真正动态的内容,其中内容是从一个完全不同的 aspx/html 页面加载的。在本文的第二部分,我将向您展示如何从 jQuery 对话框窗口执行回发,以使对话框窗口在回发结束后不会自动关闭(通常会发生这种情况)。不仅如此,我还将向您展示回发后 jQuery 对话框中更新的内容。
背景
前段时间,我们有一个需求,需要弹出一个具有真正动态内容的对话框窗口。尽管最初认为使用原生 IE 模态弹出窗口很容易实现,但我们后来决定使用 jQuery UI Dialog 框架来开发。
使用的技术和工具
- Visual Studio 2010 和 C# 用于开发示例。
- jQuery js 文件来自 1.7.1 版本。
- jQuery UI js 文件来自 1.8.17 版本。
Using the Code
为了简化概念演示,我使用了非常简单的用例场景。父页面包含两个文本框和一个按钮。用户可以在文本框中输入行数和列数。当用户点击按钮时,jQuery 对话框会弹出一个包含用户指定行数和列数的表格。
这里的重点是,根据用户的输入,我们可以加载一个包含动态内容的模态窗口,例如从服务器端动态生成表格。请记住,由于表格是从服务器端渲染的,因此用户可以访问所有服务器端数据——会话数据、.NET 缓存数据、数据库服务器数据、远程服务数据——应有尽有。用户可以使用位于远程位置的数据在 jQuery 模态对话框窗口中构建他们选择的 UI 布局!
讲了这么多,让我们看看代码吧!
将 ASPX 页面的内容加载到 jQuery 对话框窗口中
首先,我将向您展示如何使用一些动态内容加载对话框窗口。
$("#LoadDialogButton").off("click");
$(document).on("click", "#LoadDialogButton", function () {
var url = "DialogContentPage.aspx";
var divId = " #MainContentDiv";
var q1 = "?inp1=" + $("#Input1").val();
var q2 = "&inp2=" + $("#Input2").val();
url = url + q1 + q2 + divId; //url in the form 'DialogContentPage.aspx?inp1=xx&inp2=yy #MainContentDiv'
$('<div id=DialogDiv>').dialog("destroy");
$('<div id=DialogDiv>').dialog({
dialogClass: 'DynamicDialogStyle',
modal: true,
open: function () {
$(this).load(url);
},
close: function (e) {
$(this).empty();
$(this).dialog('destroy');
},
height: 350,
width: 540,
title: 'Dynamic Dialog'
});
});
如果您查看上面的代码,它是加载 jQuery 模态对话框的典型 jQuery UI 语法。但如果您查看其中的“open”属性,它会向 URL 发出请求。URL 的格式是
DialogContentPage.aspx?inp1=xx&inp2=yy #MainContentDiv
它在这里所做的是,它向这个 aspx 页面发出请求,并将父页面输入(行和列)作为查询字符串。服务器使用输入生成表格并渲染回生成的 HTML。生成的 HTML 包含一个 id 为“MainContentDiv
”的 div。所有在服务器端生成的内容都在这个 div 中。这个 div 的内容简单地加载到 jQuery 模态窗口中。
让我们看看父 aspx 页面中的代码
<asp:UpdatePanel ID="UpdatePanel" runat="server">
<ContentTemplate>
<div>
<label for="Input1">
Rows
<input type="text" id="Input1" value="1"/>
</label>
<label for="Input2">
Columns
<input type="text" id="Input2" value="2"/>
</label>
<br />
<br />
<input type="button" id="LoadDialogButton" value="Open Dialog" class="ButtonStyle" />
<asp:Button ID="ServerButton" Text = "Server Dummy Button" runat="server" OnClick="DoSomethingOnServer"/>
</div>
</ContentTemplate>
</asp:UpdatePanel>
如您所见,我将所有内容都放在一个 UpdatePanel 下,它带有一个虚拟的服务器端按钮。这对于此演示的正常工作来说并非必需,但我将整个 jQuery 对话框窗口加载按钮(id 为 LoadDialogButton 的按钮)放在其下是为了向您展示一个要点。
如果您注意到我绑定按钮“LoadDialogButton
”的点击事件的方式,我使用了以下语法:
$(document).on("click", "#LoadDialogButton", function () {
而不是最常用的
$("#LoadDialogButton").click(function () {
如果我没有使用 UpdatePanel,第二种语法在此演示中将完美运行。但在实际场景中可能会出现您使用 UpdatePanel 的情况,同时又希望 jQuery 事件也能工作。
asp:UpdatePanel 将原始内容替换为服务器返回的结果,这意味着所有以前使用 jQuery 'click' 语法绑定的 jQuery 事件将不再起作用 - 您可以尝试一下。这就是 jQuery.on 绑定点击事件语法发挥作用的地方。
从 jQuery 1.7 开始,`.on()` 方法是附加事件处理程序的首选方法。对于早期版本,`.bind()` 方法(“Click 语法”)用于将事件处理程序直接附加到元素。处理程序附加到 jQuery 对象中当前选定的元素,因此这些元素必须在调用 `.bind()` 时存在。(来源)
现在,点击“打开对话框”按钮,会弹出一个带有动态生成表格的 jQuery 对话框,如下所示:
本文的最后一部分将详细介绍点击“评估”按钮时发生的情况。
哦,我差点忘了,您还需要做一件事才能使此示例正常工作。如您所见,在此示例中,jQuery 模态窗口的全部内容是从 DialogContentPage.aspx 加载的。问题是,如果您关闭模态窗口并重新打开它,**在更改了一些输入之后**,例如行数或列数发生变化,您会发现它打开时显示的是之前打开的布局!
我想您已经猜到了发生了什么,是的,浏览器缓存了之前的页面,因此打开了那个页面。您可以通过在 DialogContentPage.aspx 的 Page_Init 中添加一些代码来轻松避免这种情况。让我们看看:
protected void Page_Init(object sender, EventArgs e)
{
// Stop Caching in IE
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
// Stop Caching in Firefox
Response.Cache.SetNoStore();
}
它的作用是,它添加了以下响应头,并确保此特定页面永不缓存(至少在 IE 和 Firefox 上)。
Cache-Control: no-cache, no-store Pragma: no-cache Expires:-1
我已在 Fiddler 中捕获了相同的内容,您可以在下面看到。
将带有服务器端组件的 div 加载到 jQuery 对话框窗口中
我们通常遇到的另一种情况是,我们需要将服务器端内容加载到 jQuery 对话框窗口中。在此示例中,我有一个 div 'LocalDialogModal
',其中包含一个 asp:Label、一个 asp:TextBox 和一个 asp:Button。asp:button 有一个服务器端方法 "SaveEmployeeBtn_Click
"。
我将向您展示如何将此 div 加载到 jQuery 模态对话框中,并且仍然能够在点击 asp:button 时调用服务器端方法。
请看放置在父页面表单标签内的 div 元素。
<div id='LocalDialogModal' style="display: none"> <span style="font-style: italic; font-size: x-small; color: Gray;">Note: This is a jQuery modal dialog which does not have dynamic content but this content has server side elements, and is defined in the parent page <br /> <asp:Label ID="lblNewName" runat="server" AssociatedControlID="TextBox_NewEmployeeName" Text="Employee Name: "></asp:Label> <asp:TextBox ID="TextBox_NewEmployeeName" runat="server" Width="100%"></asp:TextBox><br /> <br /> <asp:Button ID="SaveEmployee_Button" OnClick="SaveEmployeeBtn_Click" runat="server" Text="Save" CssClass="ButtonStyle" Style="margin: 0px;" /><br /> </div>
现在,看看将用这个 div 创建的模态对话框的 jQuery 定义。
$("#LocalDialogModal").dialog({ dialogClass: 'dialogStyle', autoOpen: false, resizable: false, draggable: false, modal: true, open: function (type, data) { $(this).parent().appendTo("form"); }, width: 500, height: 238, title: "Save Employee" });
如果你仔细观察上面的代码片段,它与你定义任何 jQuery 模态对话框几乎相同,只是在“open”属性上有一个小区别。我们有这样一句声明:
$(this).parent().appendTo("form");
这行代码对于使 div 中的服务器端按钮正常工作很重要。这行代码的作用是将渲染的 HTML 的全部内容附加到父页面现有的表单标签中。
现在,这让你困惑了吗?是的,我也被困惑了。如果你查看 parent.aspx,div 'LocalDialogModal
' 已经在 form 标签内了。为什么还要再次执行 'append' 呢?
答案在于 jQuery 默认处理对话框窗口的方式。尽管您将 div 放在 form 标签内,但当您加载它们时,整个 div 默认会渲染在 form 标签之外。因此,所有渲染的服务器端元素将无法工作,如果它们不在 form 标签内。
如果我没有加上那一行代码,我会展示渲染的 HTML。
$(this).parent().appendTo("form");
请记住,这是 jQuery 对话框窗口的默认行为。
现在,当我们把代码放入 form 标签中以附加 'localDialogModal
' div 时,渲染的 HTML 看起来如下:
现在,服务器端按钮位于表单标签内,点击它将毫无问题地调用服务器端方法 "SaveEmployeeBtn_Click
"。
从 jQuery 对话框窗口异步调用服务器端方法
要实现从 jQuery 对话框窗口内进行异步服务器调用,我们可能会考虑将 jQuery 对话框的内容放在 asp:UpdatePanel 内——但这在大多数情况下无法正常工作。您可能会遇到诸如回发后对话框窗口立即关闭、无法在对话框窗口本身中看到更新内容、对话框本身脱钩等问题。
我将向您展示如何异步调用服务器端方法,而无需担心与 jQuery 对话框相关的 asp:updatePanel
的细微差别。
让我们考虑这里展示的第一个示例,其中我们将完全不同的 aspx 内容加载到从父页面调用的 jQuery 对话框窗口中。假设子 aspx 内容中会有按钮需要进行服务器端调用,这将非常直接。
让我们看看 DialogContentPage.aspx 中的代码。
<form id="form1" runat="server"> <div id="MainContentDiv"> Dynamic Dialog Page loaded! <asp:PlaceHolder ID="DynamicPlaceholder" runat="server"></asp:PlaceHolder> <input type="button" id="EvaluateButton" value="Evaluate" class="ButtonStyle" /> <br /><br /> <div> <asp:Label ID="ResultLabel" runat="server" Height="60px" Width="400px" Style="display: none"></asp:Label> </div> </div> </form>
asp:Placeholder
将保存根据用户输入(在我们的例子中)或服务器上可用的任何数据在运行时生成的表格。
我们有一个按钮“EvaluateButton
”。我将向您展示如何通过点击此按钮调用服务器端方法并带有一些输入,在服务器上执行一些操作,然后更新 jQuery 对话框窗口本身的结果(不关闭它)——所有这些都是异步的。
让我们绑定一个 jQuery 方法,以便在点击此按钮时调用。
$(document).on("click", "#EvaluateButton", function () { var inputArray = new Array(); $("#DynamicTable").find("input").each(function (index) { //alert(this.id); inputArray[index] = $(this).val(); }); var inputArrayList = "{ inputArray: " + JSON.stringify(inputArray) + "}"; $.ajax({ type: "POST", dataType: "json", contentType: "application/json", url: "DialogContentPage.aspx/Evaluate_Click", data: inputArrayList, success: function (data) { //debugger; if (data.d.indexOf("Error") != -1) { } else { $("#ResultLabel").show(); $("#ResultLabel").text("Sum of all the contents is: " + data.d); } }, error: function (e, ts, et) { //debugger; alert(ts); } }); //ajax func end });
这里所做的事情非常简单。我获取动态生成的表格中所有文本框的输入,并创建一个 JSON 字符串。
然后,我调用 URL "DialogContentPage.aspx/Evaluate_Click",并将此 JSON 字符串作为输入。
那么这个 URL 代表什么呢?它代表在 DialogContentPage.aspx 的服务器端定义的 web 方法 'Evaluate_Click
'。好的,让我们看看。
[System.Web.Services.WebMethod] public static string Evaluate_Click(string[] inputArray) { string result = string.Empty; try { int resultInt = 0; foreach (var item in inputArray) { var input = int.Parse(item); resultInt += input; } result = resultInt.ToString(); } catch (Exception exp) { result = "error"; } return result }
这个方法非常简单——它接受一个字符串数组作为输入,并执行一些简单的操作,比如将它们全部加起来。这里的重点是,由于这是在服务器端完成的,您可以执行大量的复杂操作以实现某个结果。
还要记住两件事
- 此方法应为静态方法,并应使用属性 [
System.Web.Services.WebMethod
] 进行修饰。 - 它接受的输入名称应与下面所示的早期 JSON 创建器方法中定义的名称相同。
var inputArrayList = "{ inputArray: " + JSON.stringify(inputArray) + "}";
其余一切都非常简单——一旦 Web 方法成功返回结果,我就会将结果附加到 ResultsLabel
。
我已附上本文中所有示例的源代码。
关注点
这些是 jQuery 初学者可能经常遇到的情况,如果尝试自己实现而没有问题,可能会浪费大量时间。