使用JQUERY Tabs插件宿主IFRAMES


Posted in Javascript onJanuary 01, 2010

必备的东西:

Windows XP/Vista/7/2003/2008
Visual Studio 2005 or 2008 (download the correct version of Home Site project above)
.NET Framework 2.0 and ASP.NET AJAX 1.0
今天,很多浏览器提供了使用tab的能力去浏览更多的网页和网站。当然这是一个非常有用的功能来替代同时打开几个浏览器,但如果提供在一个页面中浏览多个网页也非常的不错。

例如,如果你的主页是由很多不同的有用的Web工具或者站点组成,一个tab页面将可能非常的有用。使用框架集,IFRAME等等,都是宿主外部内容的典型方式。这些方法允许你在单个页面上宿主多个网页。 但是使他们能正确的布局却非常不容易。 更不用说去处理页面和IFRAME的scrollbars等问题。

这篇文章中,尝试去宿主外部数据,提供了一个基本的解决方案,利用ASP.NET,AJAX和javascript 去处理一些遇到的麻烦。

计划

主旨是提供一个简单的宿主外部数据的方案,这个解决方案有下面这些简单的需求。

1、提供一个tab界面,方便浏览。

2、提供一个配置方法来添加tab

3、使每个tab页都能宿主配置的页面

基本的技术需要是:

1、仅当tab被选中的时候,加载外部的数据内容

2、保证纵向的scrollbars的设置成显示,而且仅当需要处理的数据溢出的时候,才显示scrollbars 。

3、保证该解决方案是能跨浏览器工作

解决方案的名字和主页面的名字都是 Home Site

分析

对于这个解决方案,我决定使用JQuery UI Tabs 来实现表格式的导航功能。我以前也使用过商业的开源的tab控件。但是JQuery UI Tabs 是轻量级的,实现非常地简单,而且是免费的。

除了JQuery 和tab控件以及.net提供的功能,不需要其它的控件。 VS2005 将足以结合整个项目的开发环境,选择C#作为开发语言。

我将使用一个IFRAME的宿主网站内容,由于跨站点(又名跨域)的安全限制,使用JQuery UI Tabs去宿主外部网页将无法直接工作。

设计

这里有一个为客户提供视觉上的最低限度的需求:
使用JQUERY Tabs插件宿主IFRAMES
该解决方案,将需要三种不同的功能模块:
1、配置模块
2、使用JQuery UI Tabs 插件的tab界面
3、使用IFRAME元素宿主网页内容办法。
配置模块:
一个需求的功能是是使tab可配置。 我选择最低限度,将tab的配置信息放到一个xml文件之中。虽然我可以更进一步的深入,使tab能的动态增加和删除,我决定在本文的第二篇中提供此功能。
XML文件的格式如下:
代码

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
<tab id="TabOne" displayName="Tab One" path="www.msn.com" /> 
<tab id="TabTwo" displayName="Tab Two" path="www.amazon.com" /> 
</configuration>

参数描述:
id = tab的唯一ID。这个ID不能包含空格
displayName =显示在tab头部的名字
path = 带查询参数的URL,"http://"是可选的。
配置文件的名字是:TabConfig.xml。现在必须手动添加或删除tab来更新解决方案的配置文件。
内容加载器:
可以说,没有内容加载模块是需要用IFRAME去为tab页面设置内部的列表项。但是如果IFRAME在一个通过使用锚作为每个tab列表项元素的子元素的独立的宿主网页中,我觉得在功能和测试方面没有比IFRAME的更好的控件了:
使用JQUERY Tabs插件宿主IFRAMES
如果你愿意,将内容装载器做成一个通用的模块,它接受查询字符串参数,以便正确设置IFRAME元素;参数为元素的唯一的ID,和源属性值,也就是加载该网页的URL。

另一个内容加载器的设计要求是,必须使该IFRAME负载整个页面(scrolling设置为auto)。此外,该网页body必须隐藏溢出(通过设置样式属性),以避免重复滚动条。特别是当改变浏览器的大小时。最后,滚动条的处理必须能跨浏览器。

tab界面

tab界面代码非常的简单,可以从 JQuery UI Tabs documentation说明文档中得到详细的演示代码。JQuery UI Tabs说明文档中的和我们JQuery UI Tabs具体的实现不同的地方在于:每个tab项锚的href指向内容加载页面,随后加载所需的网页到IFRAME里面。

一些额外的东西

上面的标签,我认为它很方便去用一个div来显示头,logo,甚至一些链接或菜单项。一个更好的需求,我想要头部能够折叠,能使每个标签宿主的页面能有一个最大的视觉效果。

最终的设计布局如下:
使用JQUERY Tabs插件宿主IFRAMES
代码/开发
我们从内容加载器开始,下面是标记:
代码

<%@ Page Language="C#" AutoEventWireup="true" 
CodeBehind="ContentLoader.aspx.cs" Inherits="HomeSite.ContentLoader" %> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
<title>ContentLoader</title> 
<style type="text/css"> 
.contentsBody { margin:0; overflow:hidden; } 
.contentsTable { width:100%; height:92%; valign:top; 
cellspacing:0; cellpadding:0; border:0 } 
.contentsIframe { height:100%; width:100%; marginwidth:0; 
marginheight:0; scrolling:auto } 
</style> 
</head> 
<body class="contentsBody"> 
<table class="contentsTable"> 
<tr> 
<td> 
<asp:Literal ID="Literal1" 
runat="server"></asp:Literal> 
</td> 
</tr> 
</table> 
</body> 
</html>

真正神奇的地方是css代码,我设置body 的margin 为0,设置overflow 为hidden。防止scrollbars 出现在页面的body上。
IFRAME的scrolling设置为auto,因此,如果需要滚动条,也只有IFRAME提供给它。因为在IFRAME的周围有大量不好看的空白空间,将margins 也设置为0,IFRAME的height和width被设置成100%,来确保网页内容占尽可能多的空间。请注意html标签中使用了Literal控件。正如你将看到以下的隐藏代码, 使用Literal的目的是允许后台代码注入东西到IFRAME元素中,它能构建了正确的querystring的ID和Path参数。
代码
using System; 
using System.Data; 
using System.Configuration; 
using System.Collections; 
using System.Web; 
using System.Web.Security; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.Web.UI.WebControls.WebParts; 
using System.Web.UI.HtmlControls; 
namespace HomeSite 
{ 
/// <summary> 
/// Content Loader code behind class 
/// </summary> 
public partial class ContentLoader : System.Web.UI.Page 
{ 
/// <summary> 
/// On Page Load we need to capture query string parameters, construct 
/// an IFRAME element, and inject the IFRAME element into our Literal control 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e"></param> 
protected void Page_Load(object sender, EventArgs e) 
{ 
string id = ""; 
string path = ""; 
// Validate we have valid querystring parameters 
// namely "ID" and "Path" 
if (HasValue(Request["ID"]) && 
HasValue(Request["Path"])) 
{ 
// Set our local variables 
id = Request["ID"].Trim().ToString(); 
path = Request["Path"].Trim().ToString(); 
// Prepend the path URL with http:// if needed 
if (!path.ToLowerInvariant().StartsWith("http://")) 
path = "http://" + path; 
// Construct the IFRAME element and set the Text value of the Literal control 
Literal1.Text = "<iframe class=\"contentsIframe\" " + 
"id=\"contentFrame" + id + "\" " + 
"frameborder=\"0\" src=\"" + path + 
"\"></iframe>"; 
} 
else 
{ 
// Either query parameter or both are not set or do not 
// exist (not passed as request parameters) 
Literal1.Text = "<span id=\"contentFrame\">An " + 
"error occurred while attempting to load a web page.</span>"; 
} 
} 
/// <summary> 
/// Simple static class used to validate the value of querystring 
/// parameter is not null or an empty string 
/// </summary> 
/// <param name="o">The object to check</param> 
/// <returns>Returns true if the object (string) 
/// has a value; false otherwise.</returns> 
public static bool HasValue(object o) 
{ 
if (o == null) 
return false; 
if (o is String) 
{ 
if (((String) o).Trim() == String.Empty) 
return false; 
} 
return true; 
} 
} 
}

只要你将querystring的ID和Path参数传递给它,装载的页面能够单独的运行。通过VS2005浏览网页,有URL的示例:http://localhost:49573/ContentLoader.aspx?ID=1234&Path=www.amazon.com.
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Xml;
using System.Text;
namespace HomeSite
{
    /// <summary>
    /// Tab configuration static handling class
    /// </summary>
    public static class TabConfiguration
    {
        /// <summary>
        /// This class returns a collection of TabDefinition classes created from
        /// parsing the tab definitions defined in the TabConfig.xml file.
        /// </summary>
        /// <param name"page">The Page reference
        ///         calling this class</param>
        /// <returns>ArrayList of TabDefinition classes</returns>
        public static ArrayList LoadConfiguration(Page page)
        {
            // Local container for tab definitions
            ArrayList tabList = new ArrayList();
            try
            {
                // Read the contents of the TabConfig.xml file
                StreamReader reader = new StreamReader(new FileStream(
                   page.MapPath("./TabConfig.xml"), 
                   FileMode.Open, FileAccess.Read));
                string xmlContent = reader.ReadToEnd();
                reader.Close();
                reader.Dispose();
                // Create an XML document and load the tab configuration file contents
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlContent);
                // Iterate through each tab definition, create a TabDefinition class,
                // and add the TabDefinition to the local ArrayList container
                foreach (XmlNode node in xmlDoc.SelectNodes("/configuration/tab"))
                {
                    TabDefinition tab = new TabDefinition();
                    tab.ID = node.Attributes["id"].Value;
                    tab.DisplayName = node.Attributes["displayName"].Value;
                    tab.Path = node.Attributes["path"].Value;
                    tabList.Add(tab);
                }
            }
            catch
            {
                // Do nothing
            }
            // Return the tab definition
            return tabList;
        }
    }
    /// <summary>
    /// This class serves as the container for a tab definition
    /// </summary>
    public class TabDefinition
    {
        /// <summary>
        /// Member variable for the Unique ID for the tab
        /// </summary>
        private string _id;
        /// <summary>
        /// Member variable for the displayed name of the tab
        /// </summary>
        private string _displayName;
        /// <summary>
        /// Member variable for the web page URL to host in the tab (IFRAME)
        /// </summary>
        private string _path;
        /// <summary>
        /// Property for the Unique ID for the tab
        /// </summary>
        public string ID
        {
            get { return _id; }
            set { _id = value; }
        }
        /// <summary>
        /// Property for the displayed name of the tab
        /// </summary>
        public string DisplayName
        {
            get { return _displayName; }
            set { _displayName = value; }
        }
        /// <summary>
        /// Property for the web page URL to host in the tab (IFRAME)
        /// </summary>
        public string Path
        {
            get { return _path; }
            set { _path = value; }
        }
    }
}

    请注意页面实例必须提供LoadConfiguration方法来正确引入TabConfig.xml的位置。我本可以使用XmlTextReader,但选择使用StreamReader读取整个配置文件的内容和使用XmlDocument对象解析tab的配置信息。因为我觉得快速转储整个配置文件比通过流程解析打开配置文件要好很多。使用XmlTextReader正属于这种情况。

    现在,让我们看看Home Site 的主页的标记

代码

<%@ Page Language="C#" AutoEventWireup="true" 
  CodeBehind="Default.aspx.cs" Inherits="HomeSite._Default" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Home Site</title>
    <link href="css/jquery-ui-1.7.2.custom.css" 
          type="text/css" rel="stylesheet" />
    <link href="css/Main.css" 
          type="text/css" rel="stylesheet" />
    <script src="JavaScript/jquery-1.3.2.min.js" 
          type="text/javascript"></script>
    <script src="Javascript/jquery-ui-1.7.2.custom.min.js" 
          type="text/javascript"></script>
    <script src="Javascript/jquery.hijack.min.js" 
          type="text/javascript"></script>
    <script type="text/javascript">
        // JQuery scripting
        $(document).ready(function()
        {
            var browser = navigator.appName;
            var heightAdjust = 23;
            var widthAdjust = 7;
            // Make height and width offset adjusts for non-IE browsers 
            if (browser != "Microsoft Internet Explorer")
            {
                heightAdjust = 18;
                widthAdjust = 9;
            }
            // Show the panelList UL element so we can setup the tabs
            // Please note this approach eliminates Flash of Unstyled Content (FOUC)
            $('#panelList').show();
            // Setup the jQuery UI tabs
            $('#tabPage').tabs({
                cache: true, // This ensures selecting a tab does not refresh the page
                load: function(event, ui)
                {
                    // Keep links, form submissions, etc. contained within the tab
                    $(ui.panel).hijack();
                    // Adjust the IFRAME size correctly in the browser window
                    $('.contentsIframe').width((ViewPortWidth() - widthAdjust));
                    $('.contentsIframe').height((ViewPortHeight() - 
                       $('.menuRow').height() - $('.tabs').height() - heightAdjust));
                }
            });
            // Toggle arrow button image and hide/show menu area
            $('#collapseArrow').click(function()
            {
                if ($(this).hasClass('ui-icon-circle-triangle-s'))
                {
                    $(this).removeClass('ui-icon-circle-triangle-s');
                    $(this).addClass('ui-icon-circle-triangle-n');
                    $('#menuDiv').show();
                }
                else
                {
                    $(this).removeClass('ui-icon-circle-triangle-n');
                    $(this).addClass('ui-icon-circle-triangle-s');
                    $('#menuDiv').hide();
                }
            // Adjust the IFRAME size correctly in the browser window
            $('.contentsIframe').width((ViewPortWidth() - widthAdjust));
            $('.contentsIframe').height((ViewPortHeight() - 
              $('.menuRow').height() - $('.tabs').height() - heightAdjust));
        });
        // Adjust tab header width and visible iframe window
        // height and width after the window is resized
        $(window).resize(function(){
        $('.contentsIframe').width((ViewPortWidth() - widthAdjust));
        $('.contentsIframe').height((ViewPortHeight() - 
          $('.menuRow').height() - $('.tabs').height() - heightAdjust));
        $('.ui-widget-header').width(ViewPortWidth() - widthAdjust);
        });
        // Adjust tab header height and width according to the IE client viewing area
        $('.ui-widget-header').width(ViewPortWidth() - widthAdjust);
        // Adjust the IFRAME height correctly in the browser window
        $('.contentsIframe').height((ViewPortHeight() - 
          $('.menuRow').height() - $('.tabs').height() - heightAdjust));
        });
        // Returns width of viewable area in the browser
        function ViewPortWidth()
        {
            var width = 0;
            if ((document.documentElement) && 
                (document.documentElement.clientWidth))
            {
                width = document.documentElement.clientWidth;
            }
            else if ((document.body) && (document.body.clientWidth))
            {
                width = document.body.clientWidth;
            }
            else if (window.innerWidth)
            {
                width = window.innerWidth;
            }
            return width;
        }
        // Returns height of viewable area in the browser
        function ViewPortHeight()
        {
            var height = 0;
            if (window.innerHeight)
            {
                height = window.innerHeight;
            }
                else if ((document.documentElement) && 
                         (document.documentElement.clientHeight))
            {
                height = document.documentElement.clientHeight;
            }
            return height;
        }
    </script>
</head>
<body class="mainBody" style="margin:0">
    <form id="form1" runat="server">
        <asp:ScriptManager id="ScriptManager1" runat="server" />
        <div>
            <table id="mainTable" cellpadding="0" cellspacing="0">
                <tr class="menuRow">
                    <td align="left" valign="top">
                        <span id="collapseArrow" 
                           title="Show/Hide Header" 
                           class="menuSpan ui-icon ui-icon-circle-triangle-n"></span>
                        <div id="menuDiv" 
                          class="menuDiv">This is the header area.
                                  <br /><i>Please customize this area as you set 
                                  fit; i.e. add a logo, menu options, links, 
                                  etc.</i><br /><br /></div>
                    </td>
                </tr>
                <tr>
                    <td class="tabPageCell" colspan="2" 
                             valign="top" align="left">
                        <div id="tabPage" class="contents">
                            <ul id="panelList" 
                                class="tabs" runat="server" />
                        </div>
                    </td>
                </tr>
            </table>
        </div>
    </form>
</body>
</html>

     这些代码标记非常的繁琐,我用了很多内部的注释来解释他们。请注意出现在标头区的左上角的箭头按钮,其实就是来自我选择的JQuery的主题中的图像文件,使用ui-icon 和ui-icon-circle-triangle-n causes 设置collapseArrow span ,造成JQuery 显示一个名字为ui-icon-circle-triangle-n的ico的图像。在文档头部的脚本区中,我创建一个函数,当我们单击它的时候,改变向上箭头图标为向下箭头图标,此外,同样的单击事件处理程序将显示或隐藏标头部域的div(menuDiv)。

Home Site 页面的隐藏代码如下:

代码

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace HomeSite
{
    /// <summary>
    /// Home Site (default) web page code behind class
    /// </summary>
    public partial class _Default : System.Web.UI.Page
    {
        /// <summary>
        /// On page load we need to create the tab
        /// list items for tab interface construction
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
                AddTabsToForm();
        }
        /// <summary>
        /// This method calls to our business logic
        /// class to read the tab configuration file,
        /// which will return an ArrayList of TabDefinition
        /// classes. This method iterates
        /// through the ArrayList building HTML controls to add to the tab panel.
        /// </summary>
        protected void AddTabsToForm()
        {
            foreach (TabDefinition tab in TabConfiguration.LoadConfiguration(this.Page))
            {
                HtmlGenericControl tabListItem = new HtmlGenericControl();
                tabListItem.TagName = "li";
                tabListItem.InnerHtml = "<a title=\"" + 
                  tab.DisplayName + "\" href=\"ContentLoader.aspx?ID=" + 
                  tab.ID + "&Path=" + tab.Path + 
                  "\">" + tab.DisplayName + "</a>";
                panelList.Controls.Add(tabListItem);
            }
        }
    }
}

隐藏代码不需要做过多的解释,关键的动作是创建和设置HtmlGenericControl列表项,最后它通过编程被添加tab panel中。

遇到的问题

我遇到的主要的问题是跨浏览器的情况下自动适应IFRAME的大小,该方案在IE 8,Firefox v3.5.6,和谷歌v3.0.195.38浏览器进行测试。

我必须进行浏览器检测,根据IFRAME在三个浏览器测试的尺寸,调整相应的宽度和高度。当浏览器改变大小的时候,Chrome 和FireFox看起来IFRAME有个固定的高度。 但是, IE8看来来会丢失在IFRAME和浏览器顶部之间的padding。调整宽度和高度特别是IE似乎应该尽可能的减少IFRAME到IE浏览器窗口的底部“蜷缩”影响。

限制

1、以下JavaScript将使你加载的网页跳出IFRAME,我不知道任何解决办法此(如果存在)。Code Project 网站上目前拥有类似下面的代码,这样配置选项指向http://www.codeproject.com/非常的容易,这里重现描述的动作。

<script type="text/javascript" language="javascript">
    if (top!=self) top.location.href = location.href;
</script>
2、在浏览器中,Web网页被迫改变页面本身的大小,有可能跳出IFRAME窗体,从而取代了前父窗口。

3、我没有使用Safari,Opera,早期版本的IE浏览器,或任何其他浏览器的早期版本测试的此解决方案,所以要在Home Site中适当地调整heightAdjust和widthAdjust变量,适应没有测试的IE浏览器或低于IE8浏览器的版本。

总结和兴趣点
虽然这种解决方案不是很复杂,通过一个标签界面宿主外部网站内容。这是我所见过的许多网络论坛和博客要求的功能。请注意:您也可以配置标签可显示自己相关的域名或网站(在同一台服务器)。

Javascript 相关文章推荐
jquery 模式对话框终极版实现代码
Sep 28 Javascript
一款js和css代码压缩工具[附JAVA环境配置方法]
Apr 16 Javascript
jquery 新建的元素事件绑定问题解决方案
Jun 12 Javascript
Jquery 实现图片轮换
Jan 28 Javascript
遍历json 对象的属性并且动态添加属性的实现
Dec 02 Javascript
微信小程序 合法域名校验出错详解及解决办法
Mar 09 Javascript
js实现分页功能
May 24 Javascript
Angularjs 事件指令详细整理
Jul 27 Javascript
React如何避免重渲染
Apr 10 Javascript
详解如何写出一个利于扩展的vue路由配置
May 16 Javascript
JQuery Ajax如何实现注册检测用户名
Sep 25 jQuery
JS将指定的某个字符全部转换为其他字符实例代码
Oct 13 Javascript
用jquery实现学校的校历(asp.net+jquery ui 1.72)
Jan 01 #Javascript
url 特殊字符 传递参数解决方法
Jan 01 #Javascript
JavaScript 数组循环引起的思考
Jan 01 #Javascript
javascript eval和JSON之间的联系
Dec 31 #Javascript
js下用gb2312编码解码实现方法
Dec 31 #Javascript
JavaScript 学习笔记(七)字符串的连接
Dec 31 #Javascript
JavaScript 学习笔记(六)
Dec 31 #Javascript
You might like
PHP输出一个等腰三角形的方法
2015/05/12 PHP
PHP使用NuSOAP调用Web服务的方法
2015/07/18 PHP
php实现zip文件解压操作
2015/11/03 PHP
CI框架表单验证实例详解
2016/11/21 PHP
游戏人文件夹程序 ver 4.03
2006/07/14 Javascript
js textarea自动增高并隐藏滚动条
2009/12/16 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
nodejs实现HTTPS发起POST请求
2015/04/23 NodeJs
JavaScript用200行代码制作打飞机小游戏实例
2017/06/21 Javascript
Vue resource中的GET与POST请求的实例代码
2017/07/21 Javascript
r.js来合并压缩css文件的示例
2018/04/26 Javascript
使用json-server简单完成CRUD模拟后台数据的方法
2018/07/12 Javascript
详解Angular6学习笔记之主从组件
2018/09/05 Javascript
微信小程序实现圆形进度条动画
2020/11/18 Javascript
JavaScript 俄罗斯方块游戏实现方法与代码解释
2020/04/08 Javascript
JavaScript ES 模块的使用
2020/11/12 Javascript
python调用新浪微博API项目实践
2014/07/28 Python
Python多线程编程(七):使用Condition实现复杂同步
2015/04/05 Python
python 中的int()函数怎么用
2017/10/17 Python
python+selenium打印当前页面的titl和url方法
2018/06/22 Python
Python 普通最小二乘法(OLS)进行多项式拟合的方法
2018/12/29 Python
pip 安装库比较慢的解决方法(国内镜像)
2019/10/06 Python
python sklearn包——混淆矩阵、分类报告等自动生成方式
2020/02/28 Python
Python+redis通过限流保护高并发系统
2020/04/15 Python
python os模块常用的29种方法使用详解
2020/06/02 Python
OpenCV4.1.0+VS2017环境配置的方法步骤
2020/07/09 Python
CSS3中的5个有趣的新技术
2009/04/02 HTML / CSS
亚洲最大旅游体验平台:KKday
2017/10/21 全球购物
美国婴儿和儿童家具网上商店:ABaby.com
2018/07/02 全球购物
Zooplus罗马尼亚:宠物食品和配件
2019/11/02 全球购物
为什么要使用servlet
2016/01/17 面试题
四风问题查摆材料
2014/08/25 职场文书
部队2014年终工作总结
2014/11/27 职场文书
学校捐书倡议书
2015/04/27 职场文书
2016年习主席讲话学习心得体会
2016/01/20 职场文书
优秀党员先进事迹材料2016
2016/02/29 职场文书