必备的东西:
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去宿主外部网页将无法直接工作。
设计
这里有一个为客户提供视觉上的最低限度的需求:
"\"></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="/UploadFiles/2021-04-02/jquery-1.3.2.min.js"> type="text/javascript"></script>
<script src="/UploadFiles/2021-04-02/jquery-ui-1.7.2.custom.min.js"> type="text/javascript"></script>
<script src="/UploadFiles/2021-04-02/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浏览器的版本。
总结和兴趣点
虽然这种解决方案不是很复杂,通过一个标签界面宿主外部网站内容。这是我所见过的许多网络论坛和博客要求的功能。请注意:您也可以配置标签可显示自己相关的域名或网站(在同一台服务器)。
JQUERY,Tabs
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。