使用 jQuery 和 Json 在 ASP.NET MVC 中动态生成承载 IFrames 的选项卡
本文介绍了一种使用 jQuery 和 Json 在 ASP.NET MVC 中动态生成承载 IFrames 的选项卡的方法。
引言
本文介绍了一种使用 "IFrames"、"jQuery" 和 "Json" 在 "ASP.NET MVC" 中动态生成承载 IFrames 的选项卡的方法。
背景
"IFrames" 在 "Web Development" 中已被使用了很长时间,以提高网站的响应能力和用户体验。"IFrames" 还可以通过将应用程序分割成逻辑相关的块来提供一些编程优势。在某些情况下,最好将 "IFrames" 组织在 "选项卡" 中。"jQuery" 提供了一种非常好的方式来创建 "选项卡"。本文将通过一个示例介绍一种使用 jQuery 和 Json 在 ASP.NET MVC 中动态生成承载 IFrames 的选项卡的方法。
本文的灵感来自于 Matt Esterak 的文章 "使用 JQuery UI Tabs 插件承载 IFRAME"。本文利用 ASP.NET MVC 的一些新功能和 "Json" 支持来动态生成承载 IFrames 的选项卡。每个选项卡的信息在 MVC 控制器中配置,并通过 jQuery 以 Json 格式加载到客户端。
示例项目是在 "Visual Studio 2010" 和 "MVC 2" 中开发的。本例中使用的 jQuery 版本是 "1.4.2"。用于服务器端操作的语言是 "C#"。以下是 Visual Studio "解决方案资源管理器" 的屏幕截图。
ASP.NET MVC 2 项目 "DynamicJsonIFrame
" 是一个简单的 Web 项目。它包含以下主要组件:
- 在 "Models" 文件夹中,项目包含一个名为 "
TabInfo
" 的模型类。 - 在 "Controllers" 文件夹中,项目包含一个名为 "
HomeController
" 的控制器。 - 与 "
HomeController
" 对应的有三个 "视图":"Index.aspx"、"IFrameContainer.aspx" 和 "IFrameWebLoader.aspx"。"Index.aspx" 是主应用程序 Web 页面。"IFrameContainer.aspx" 和 "IFrameWebLoader.aspx" 用于创建和加载 IFrames。 - "Index.aspx" 使用了一个名为 "
Site.Master
" 的母版页。
除了标准的 jQuery 库 "jquery-1.4.2.min.js" 之外,示例应用程序还需要 "jQuery Plug-in" "jquery-ui-1.8.5.custom.min.js" 和 "Stylesheet" 文件 "jquery-ui-1.8.5.custom.css"。您可以从 此处 下载这些文件。本文假设读者对 ASP.NET MVC、jQuery 和 Json 有一些基本了解。如果您对此类主题不熟悉,应该可以在网上轻松找到参考资料。
首先,让我们看一下模型类 "TabInfo
"。
模型类 "TabInfo"
项目中唯一的模型类是 "TabInfo.cs" 中实现的 "TabInfo
" 类。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DynamicJsonIFrame.Models
{
public class TabInfo
{
public int TabID { get; set; }
public string TabText { get; set; }
public string TabInformationText { get; set; }
public string TabUrl { get; set; }
}
}
公共属性用于保存每个选项卡项的信息。"TabText
" 是在选项卡项上显示的文本。"TabInformationText
" 用于示例项目中选项卡项的工具提示。"TabUrl
" 是激活选项卡项时要加载的网页的 URL。
控制器 "HomeController"
"HomeController
" 实现如下:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using DynamicJsonIFrame.Models;
namespace DynamicJsonIFrame.Controllers
{
[HandleError]
public class HomeController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index(){ return View(); }
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult IFrameContainer(string WebURL,
string InformationText)
{
ViewData["WebURL"] = WebURL;
ViewData["InformationText"] = InformationText;
return View();
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult IFrameWebLoader(string WebURL)
{
ViewData["WebURL"] = WebURL;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GetTabs()
{
List<TabInfo> tabList = new List<TabInfo>();
tabList.Add(new TabInfo
{
TabID = 1,
TabText = "Yahoo",
TabInformationText = "",
TabUrl = "http://www.yahoo.com"
});
tabList.Add(new TabInfo
{
TabID = 2,
TabText = "Hall of fame",
TabInformationText
= "Michael Jordan's hall of fame acceptance speech",
TabUrl = "http://www.youtube.com/watch?v=owbYN3XstVQ"
});
tabList.Add(new TabInfo
{
TabID = 2,
TabText = "Soccer Game",
TabInformationText = "The greatest soccer goal",
TabUrl = "http://www.youtube.com/watch?v=MsAgu45qqWE"
});
tabList.Add(new TabInfo
{
TabID = 2,
TabText = "Cool",
TabInformationText = "Soccer and soccer !",
TabUrl = "http://www.youtube.com/watch?v=X5SwdvUWx0E"
});
return Json(tabList);
}
}
}
在此控制器中,有四个 "Action Methods"。"Index
"、"IFrameContainer
" 和 "IFrameWebLoader
" 这三个 Action Methods 是标准的 Action Methods。这三个 Action Methods 中的每一个都只是返回一个 "ActionResult",将程序流程引导到 "Views\Home" 文件夹中的相应视图。最后一个 Action Method "GetTabs
" 没有对应的视图。它返回一个 "JsonResult"。我将几个 "TabInfo
" 对象硬编码到一个 "List" 中。在真实的 Web 应用程序中,这个 List 可以从任何配置源(例如数据库)动态创建。此 Action Method 将从 "Index.aspx" 中的一个 jQuery 客户端通过 Ajax 调用进行访问。
"Index.aspx" 视图和 "Site.Master"
在看 "Index.aspx" 之前,让我们先看一下 "Site.Master
"。
<%@ Master Language="C#"
Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>
<asp:ContentPlaceHolder ID="TitleContent" runat="server" />
</title>
<link rel="SHORTCUT ICON"
href="<%= Url.Content("~/Images/pig_mac_archigraphs.ico") %>" />
<link rel="stylesheet" type="text/css"
href="<%= Url.Content("~/Styles/AppStyle.css") %>" />
<link rel="stylesheet" type="text/css"
href="<%= Url.Content("~/Styles/jquery-ui-1.8.5.custom.css") %>" />
<script type="text/javascript"
src="<%= Url.Content("~/Scripts/jquery-1.4.2.min.js") %>">
</script>
<script type="text/javascript"
src="<%= Url.Content("~/Scripts/jquery-ui-1.8.5.custom.min.js") %>">
</script>
</head>
<body>
<div>
<div>
<div id="Header">
<h1>Dynamic Creation of Tabs for IFrames using
jQuery and Json in MVC</h1>
<label class="Author">Developed By Song Li
- 9/23/2010</label>
</div>
</div>
<div>
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<div id="Footer"><h1>The Code Project Open License (CPOL)
2010 - 2020®</h1></div>
</div>
</body>
</html>
除了显示 Web 应用程序的页眉和页脚之外,"Site.Master
" 还有一个名为 "MainContent
" 的 "ContentPlaceHolder"。"Index.aspx" 将使用此 "ContentPlaceHolder" 向 Web 应用程序添加 HTML 和 JavaScript 内容。"Index.aspx" 实现如下:
<%@ Page Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="TitleContent"
ContentPlaceHolderID="TitleContent" runat="server">
IFrame host with dynamically generated jQuery Tabs
</asp:Content>
<asp:Content ID="MainContent"
ContentPlaceHolderID="MainContent" runat="server">
<!-- This is the place holder for the dynamically generated tabs -->
<div id="MainTabs" class="FluidContent">
<div id="divTabs" class="iframeMax"></div>
</div>
<script type="text/javascript">
var GetTabsUrl = '<%: Url.Action("GetTabs", "Home") %>';
var IFrameContainerUrl = '<%: Url.Action("IFrameContainer", "Home") %>';
$(document).ready(function () {
$.ajax({
cache: false,
type: "POST",
url: GetTabsUrl,
dataType: "json",
success: function (data) {
var GenerateTabs = function () {
var tabui = document.createElement("ul");
$.each(data, function () {
var li = document.createElement("li");
var a = document.createElement("a");
a.href = IFrameContainerUrl + "?WebURL="
+ escape(this.TabUrl)
+ "&InformationText="
+ escape(this.TabInformationText);
var span = document.createElement("span");
$(span).attr("title", this.TabInformationText);
var tx = document.createTextNode(this.TabText);
span.appendChild(tx)
a.appendChild(span);
li.appendChild(a);
tabui.appendChild(li);
});
$("#divTabs").html("").append(tabui);
var $tabs = $("#divTabs").tabs({
cache: true,
selected: -1,
select: function (event, ui) {
return true;
}
}).ajaxComplete(function (event, request, settings) {
return;
});
if (data.length > 0) {
$tabs.tabs('select', 0);
}
};
GenerateTabs();
},
error: function (xhr) {
var status = xhr.status;
var responseText = xhr.responseText;
alert("Error occurred when load the information for the tabs");
}
});
});
</script>
</asp:Content>
"Index.aspx" 是创建动态选项卡的主要位置。ID 为 "divTabs
" 的 Div 是动态选项卡的 HTML 占位符,它是实现此功能所必需的唯一元素。选项卡的创建发生在 JavaScript 部分的 "$.ajax" 调用中。
- 它首先对 "
HomeController
" 中的 "GetTabs
" Action Method 进行一次 Ajax 调用。 - 如果调用成功,"
TabInfo
" 对象列表将作为 Json 对象数组传递给 "$.ajax" 调用 "success
" 参数对应的 "匿名函数"。 - "
GenerateTabs
" 函数将使用每个 Json 对象中的信息来构建 jQuery 选项卡的 HTML UI 元素,并将它们附加到 ID 为 "divTabs
" 的 Div 中。如果您想了解 jQuery 选项卡所需的 HTML UI 元素的详细信息,可以参考 此链接。 - 在 UI 元素构建并添加到 DOM 后,jQuery 调用 "
$("#divTabs").tabs()
" 将创建动态选项卡,而 "$tabs.tabs('select', 0)
" 语句将激活第一个选项卡。
您可能需要注意的一点是,传递给每个选项卡项的 URL 不是来自 Json 对象的真正 "TabUrl
"。选项卡项要加载的内容 URL 是 "IFrameContainer.aspx" 文件。
接下来,让我们看一下 "IFrameContainer.aspx"。
"IFrameContainer.aspx" 和 "IFrameWebLoader.aspx" 视图
"IFrameContainer.aspx" 实现如下:
<%@ Page Language="C#"
Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<html>
<head runat="server">
<title></title>
</head>
<body>
<iframe class="iframeInner"
frameborder="0" scrolling="auto"
src="<%= Url.Action("IFrameWebLoader", "Home",
new {WebURL = ViewData["WebURL"]}) %>" />
</body>
</html>
"IFrameContainer.aspx" 文件是放置 "Iframe" 标签的地方。当用户单击一个选项卡项时,jQuery tabs 会进行一次 Ajax 调用以检索 "IFrameContainer.aspx" 页面的内容,然后将内容插入到 "Index.aspx" 页面中。如果将 "Iframe" 的 "src" 属性设置为 "TabUrl
",则会加载 Json 对象中指定的所需网页。在本例中,我没有直接将 "Iframe" 的 "src" 属性设置为 "TabUrl
"。而是将其设置为 "IFrameWebLoader.aspx",该页面实现如下:
<%@ Page Language="C#"
Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link rel="stylesheet" type="text/css"
href="<%= Url.Content("~/Styles/WebLoaderStyle.css") %>" />
<script type="text/javascript"
src="<%= Url.Content("~/Scripts/jquery-1.4.2.min.js") %>">
</script>
<script type="text/javascript">
$(document).ready(function () {
document.location.replace($("#WebURL").val());
});
</script>
</head>
<body>
<input type="hidden" id="WebURL"
value="<%= ViewData["WebURL"]%>" />
<div id="WaitInfo">
Page loading, please wait ...
</div>
</body>
</html>
"IFrameWebLoader.aspx" 在一个隐藏字段中保存了 "TabUrl
"。在 "$(document).ready
" 事件中,我使用 JavaScript 读取隐藏字段并将页面重定向到 "TabUrl
"。这个中间步骤不是绝对必需的。它只是为了在用户需要加载的网页加载时间较长时,向用户提供某种视觉反馈。我为此目的显示文本 "页面正在加载,请稍候..." 并将此页面的 "cursor" 设置为 "wait"。由于 "IFrameWebLoader.aspx" 页面非常小,因此开销应该最小。
在 Iframes 中承载外部网页
在许多情况下,使用 IFrames 承载网页是一个好主意。但如果您正在承载您无法控制的外部网页,则需要小心。我最近从一位同事那里得知,如果作者不希望有人在 IFrames 中承载他们的网页,他们可以通过一行 JavaScript 代码在其页面中放置一个 "Frame Buster"。
<script type="text/javascript">
if (top != self) top.location.replace(self.location.href);
</script>
这个简单的 "Frame Buster" 非常有效。如果它发现网页是在框架中承载的,它就会破坏框架并接管整个 Web 浏览器窗口。虽然有些人研究过 "Framekiller",但它们似乎只能有限地 "杀死" Frame Busters。
如果您的目的是在 IFrames 中承载您自己的网页,您应该不会遇到任何问题,除非您想在 Web 应用程序中混合使用 "http/https"。在这种情况下,您的用户可能会看到一些警告消息。
运行应用程序
现在让我们运行我们的应用程序。在应用程序中,我添加了几个选项卡。一个选项卡加载 "Yahoo",其他选项卡加载一些 "Youtube" 视频。Yahoo 和 Youtube 都没有 "Frame Busters"。如果您单击一个选项卡,您会注意到 Json 对象中放置的网页已加载。下图显示了加载 Youtube 视频的选项卡。
关注点
- 本文介绍了一种使用 jQuery 和 Json 在 ASP.Net MVC 中动态生成承载 IFrames 的选项卡的方法。
- Json 的内容可以在 MVC 控制器中配置,并通过 Ajax 调用加载到客户端。
- jQuery 选项卡是通过 jQuery Plug-in 创建的。您可以参考 此链接 以获取更多详细信息。
- 示例项目没有直接将 Iframe 的 src 属性设置为所需网页,而是转到一个中间页面,以便在加载所需网页时间较长时告知用户。
- 如果您想在 IFrames 中承载外部网页,您应该注意 Frame Busters。
- 希望您喜欢我的帖子,也希望这篇文章能以某种方式帮助您。
历史
- 这是本文的第一个修订版。