#中.net中得IO类虽然功能很强大,但是正是因为功能强大,所以在很多虚拟服务商的服务器上并不实用 。因为IO.Directory和IO.DirectoryInfo在应用文件夹操作中,会遍历网站所在的硬盘的磁盘跟目录,一般虚拟服务商并不会给这个磁盘的Network service用户开启读取权限,所以在操作文件夹的时候,使用IO下的这两个类会出现如下错误
未找到路径“E:\”的一部分。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: System.IO.DirectoryNotFoundException: 未找到路径“E:\”的一部分。
源错误:
执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。
堆栈跟踪:
[DirectoryNotFoundException: 未找到路径“E:\”的一部分。]
System.IO.__Error.WinIOError(Int32 errorCode, String str) 287
System.IO.Directory.InternalCreateDirectory(String fullPath, String path) 489
System.IO.Directory.CreateDirectory(String path) 195
-----------------------
版本信息: Microsoft .NET Framework 版本:1.1.4322.2300; ASP.NET 版本:1.1.4322.2300
其中未找到路径E:/,E盘就是服务器上磁盘路径,可能会因为服务器的不同而不同。面对这个问题,服务商又不肯给你多开权限的情况下,应该怎么解决呢?
呵呵,可能是因为我基础比较差,于是上网寻求解答,但是苦苦找不到答案。偶然的一次,发现asp可以应用fso创建文件夹。于是想到用asp.net调用window中得fso组件。呵呵,居然成功了,特写这篇文章给那些苦于此问题不得解决的朋友和兄弟。
项目->引用 浏览 COM组件 Microsoft Scripting Runtime
Scripting.FileSystemObject fso=new Scripting.FileSystemObjectClass();
fso.CreateFolder(Path)
就可以了,不过此种解决方法的前提是虚拟服务商开启了FSO
至于IO操作文件夹得两个类为什么会遍历磁盘根目录还在研究中,不过问题终于解决了,希望了解此的人能给大家一个答案。
ASP.net 2.0 有一个新特性,就是支持应用程序离线信息。
什么是离线信息呢?以前我们在更新应用程序,导至asp.net应用程序重启,应用程序的用户通常会显示不友好的错误信息,或者IE一直显示加载状态。
ASP.net 2.0支持您在应用程序根目录下放置一个app_offline.htm文件,用户请求时,系统会检查是否有这个文件存在,如果有,系统会将app_offline.htm文件的内容直接返回给用户。
app_offline.htm的内容可以更改成任何您需要的内容,但是要注意,文件不能太小,因为大部分用户的IE设置了“显示友好的Http错误信息”,如果app_offline.htm小于512字节,此设置将会失效。
另外注意一下地址栏,offline信息显示时,地址栏依然显示的时请求的地址
以上我在iss6下测试成功
在asp.net2.0中新增了对web.config中的部分数据进行加密的功能,可以使用RSAProtectedConfigurationProvider和DPAPIProtectedConfigurationProvider来加密,本文说明使用RSAProtectedConfigurationProvidert和计算机级别的密钥容器进行加密的步骤。
1. 首先确定要进行加密的web.config中的配置节是否可以加密
2. 创建RSA密钥容器
3. 在web.config中标识要使用的密钥容器
4. 对web.config进行加密
5. 授予对 RSA 密钥容器的访问权限
Step 1:首先确定要进行加密的web.config中的配置节是否可以加密
ASP.NET 2.0支持对Web.config的部分配置节进行加密,以下配置节中的数据是不能进行加密的:
<processModel>
<runtime>
<mscorlib>
<startup>
<system.runtime.remoting>
<configProtectedData>
<satelliteassemblies>
<cryptographySettings>
<cryptoNameMapping>
<cryptoClasses>
Step2:创建 RSA 密钥容器
若要创建 RSA 密钥容器,请使用 ASP.NET IIS 注册工具 (Aspnet_regiis.exe) 及 –pc 开关。必须为密钥容器指定一个名称,该名称标识应用程序的 Web.config 文件的 configProtectedData 节中指定的 RsaProtectedConfigurationProvider 所使用的密钥容器。为确保可以导出新创建的 RSA 密钥容器,必须包括 -exp 选项。
例如,下面的命令创建一个名为 ABeenKeys 的 RSA 密钥容器,该容器是可导出的计算机级密钥容器。
aspnet_regiis -pc "ABeenKeys"–exp
Step 3: Modify web.config to identify the key container
编辑Web.config文件以标识要使用的密钥容器
在web.config中加以<configProtectedData>来配置密钥容器, 使用名为 ABeenKeys 的计算机级 RSA 密钥容器的
在<configuration>中加入xmlns属性
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">使用名为 ABeenKeys 的计算机级 RSA 密钥容器的 saProtectedConfigurationProvider。
<configProtectedData > <providers> <add name="ABeenProvider" type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0,Culture=neutral, processorArchitecture=MSIL" keyContainerName="ABeenKeys"/> </providers> </configProtectedData>
Step 4: Encrypt the <connectionStrings> section of your web.config file
加密你的web.config文件中的配置节
> aspnet_regiis -pe "connectionStrings" -app "/connectionTest"
Step 5:授予对 RSA 密钥容器的访问权限
可以通过以下代码确定应该给哪个用户权限
Response.Write(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
默认情况下,RSA 密钥容器受到所在服务器上的 NTFS 访问控制列表 (ACL) 的严密保护。这样能够限制可以访问加密密钥的人员,从而增强加密信息的安全性。必须首先向 ASP.NET 应用程序的进程标识授予对该 RSA 密钥容器的读取访问权限,然后 ASP.NET 才能使用 RSA 密钥容器。可以使用 Aspnet_regiis.exe 工具及 -pa 开关,向 ASP.NET 应用程序的标识授予读取 RSA 密钥容器的权限。例如,下面的命令向 Windows Server 2003 NETWORK SERVICE 帐户授予对名为 ABeenKeys 的计算机级 RSA 密钥容器的读取访问权限:
aspnet_regiis -pa "ABeenKeys" "NT AUTHORITY\NETWORK SERVICE"
注意:
如果 RSA 密钥容器是用户级容器,必须以其 Windows 配置文件存储了密钥的用户的身份登录,并且必须包括 -pku 选项以授予对该用户级 RSA 密钥容器的访问权限。
若要使用计算机配置中指定的默认 RsaProtectedConfigurationProvider,必须首先向应用程序的 Windows 标识授予对名为 NetFrameworkConfigurationKey 的计算机密钥容器的访问权限,该计算机密钥容器是为该默认提供程序指定的密钥容器。例如,下面的命令向 NETWORK SERVICE 帐户授予对默认 RsaProtectedConfigurationProvider 所使用的 RSA 密钥容器的访问权限。
aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"
NetFrameworkConfigurationKey RSA 密钥容器是 Aspnet_regiis.exe 工具所发出的命令的默认密钥容器。因此上述命令也可以按以下方式发出:
aspnet_regiis -pa "NT AUTHORITY\NETWORK SERVICE"
注意:我发现这个方法有个缺陷,哪就是在每次加密完后,重新启动机算机发现IIS admin出错了,还得重新安装 iis 郁闷
试用了一下asp.net 2.0的上传控件,还是挺方便的。
分享代码如下:
protected void Button1_Click(object sender, EventArgs e)
{
try
{
判断文件大小#region 判断文件大小
int intFileLength = this.FileUpload1.PostedFile.ContentLength;
if (intFileLength > 50000)
{
this.Label1.Text = "文件大于50k,不能上传";
return;
}
#endregion
判断保存的文件夹是否存在#region 判断保存的文件夹是否存在
string strUpPath = @"upfile\" System.DateTime.Now.ToShortDateString();// @"\";
//文件夹不存在的时候,创建文件夹
if (!System.IO.Directory.Exists(Server.MapPath(strUpPath)))
{
System.IO.Directory.CreateDirectory(Server.MapPath(strUpPath));
}
string strUrl = Server.MapPath(strUpPath @"\" this.FileUpload1.FileName);
#endregion
//上传文件
this.FileUpload1.SaveAs(strUrl);
this.Label1.Text = "文件上传成功";
}
catch (System.Exception ex)
{
this.Label1.Text = "文件上传失败:" ex.Message;
}
}
本文结合示例讲述了在ASP.net应用程序中如何利用客户端的javascript脚本提高程序的执行效率并实现更多的功能。
一、ASP.Net与Javascript
.Net是微软公司下一代的战略核心,ASP.Net是.Net战略在Web开发方面的具体实现。它继承了ASP的简单性和易用性,同时克服了ASP程序结构化较差,难于阅读和理解的缺点。特别是服务器端控件和事件驱动模式的引入,使得Web应用程序的开发更接近于过去桌面程序的开发。
在各种各样介绍ASP.Net的文章和书籍中,都把重点放在了服务器控件和.Net Framework SDK上,因为这是ASP.Net中最新和最具革命性的改进;与此相反,在过去的Web开发中占据重要地位的客户端脚本Javascript(也包括VBScript)则鲜有提及,似乎有了服务器端程序,已经不需要客户端脚本了。但是,服务器端的程序毕竟需要一次浏览器与Web服务器的交互,对于ASP.Net来说,就是一次页面的提交,需要来回传送大量的数据,而很多工作,比如输入验证或者删除确认等,完全可以用Javascript来实现。因此,探讨在ASP.Net中如何使用Javascript仍然很有必要。
二、Javascript的应用示例
1.为页面上的某个服务器控件添加Javascript事件
服务器控件最终生成的仍然是普通的HTML,比如<asp:textbox>生成input text。表单中的每个HTML控件都有它自己的Javascript事件,比如Textbox有onchange事件,Button有onclick事件,Listbox有onchange事件等。要想为服务器控件添加客户端的事件,需要用到Attributes属性。Attributes属性是所有的服务器控件都有的一个属性,它用来为最终生成的HTML添加自定义的一些标记。假设Web Form上有一个保存按钮btnSave,希望在用户点此按钮时提示用户是否确实要保存(比如一旦保存就无法恢复等),则应在Page_Load事件中添加如下代码:
if not page.isPostBack() then
btnSave.Attributes.Add(“onclick”,”Javascript:return confirm(‘Are you sure to save?’);”)
end if
要注意的是‘return’,这是不可省的,否则即使用户点了取消,数据仍然会保存。
2.为Datagrid中的每一行添加Javascript事件
假设Datagrid的每一行有一个删除按钮,希望在用户点此按钮时提示用户是否确实要删除此条记录,以防用户点错了行,或仅仅是无意中点了删除按钮。
无论这个删除按钮是什么名字,都不能象上个例子那样直接引用,因为每一行都有这样一个按钮,它们是Datagrid中的子控件。在这种情况下,需要用到Datagrid的OnItemDataBound事件。OnItemDataBound事件发生在Datagrid的每一行数据绑定到Datagrid之后(即一行激发一次)。首先在Datagrid的声明中添加如下代码:
<asp:datagrid id="grd1" runat="server" OnItemDataBound = "ItemDataBound" >
…Columns definition here
</asp:datagrid> 此处说明OnItemDataBound事件发生时调用ItemDataBound方法,在代码后置文件中添加此方法的定义:
Sub ItemDataBound(ByVal sender As Object, ByVal e As DataGridItemEventArgs)
If e.Item.ItemType <> ListItemType.Header And e.Item.ItemType <> ListItemType.Footer Then
Dim oDeleteButton As LinkButton = e.Item.Cells(5).Controls(0)
oDeleteButton.Attributes("onclick") = "javascript:return Confirm ('Are you sure you want to delete" & DataBinder.Eval(e.Item.DataItem, "m_sName") & "?')"
End If
End Sub
由于Datagrid的标题行和脚注行也会激发此事件,所以首先判断激发此事件的行不是标题行和脚注行。这里假设Delete按钮位于Datagrid的第6列(第一列是0),且Datagrid的Datasource中包含名为”m_sName”的列
3.引用编辑状态下的Datagrid中的控件
Datagrid的内置编辑功能使得当记录的字段较少时的一种编辑方法。用户不必进入一个单独的页面编辑记录,而是直接点编辑按钮就可以使当前行进入编辑模式。而另一方面,有一些Javascript程序需要引用控件的名称。比如,很多程序在需要用户输入日期时都提供一个日期控件以保证日期格式的合法性,当用户点控件图标时弹出一个新窗口供用户选择日期。此时需要把显示日期的文本框的ID提供给新窗口,以便当用户选择日期后值可以回填到文本框中。
如果是普通的服务器文本框控件,它的ID与生成的HTML输入框的ID是相同的;但是在Datagrid的编辑状态下,两个ID并不相同(其道理与上例相同),这就需要用到控件的ClientID属性。
Protected Sub ItemEdit(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Dim sDateCtrl as string
sDateCtrl = grd1. Items (e.Item.ItemIndex) . Cells(2). FindControl("txtDate") . ClientID
End Sub
这里假设ItemEdit方法是Dategrid的OnItemEdit事件处理程序,同时在Datagrid的第三列包含一个名为txtDate的服务器文本框控件。
4.引用ASP.Net自动生成的Javascript程序
所谓的“服务器端控件”是针对开发人员的,在生成的HTML源程序中并没有服务器和客户端之分,都是标准的HTML,DHTML和Javascript。它之所以能响应用户的输入是因为每个控件的事件处理程序最终都生成了一段脚本,此脚本重新提交页面使得Web Server有机会再次响应并作出处理。通常情况下我们不必知道此脚本是什么也不必直接调用此脚本,但在有些情况下,适当地调用此脚本可以简化许多工作。请看下面两个例子。
● 点Datagrid的任一位置以选中一行
Datagrid提供了一种内置的选择按钮,当点此按钮时选中当前行(可以设置SelectedItemStyle属性以使当前行有不同的外观)。但用户可能更习惯于点任意一个位置都能选中一行,如果完全自己实现这个功能相当烦琐。一个好的思路是添加一个选择按钮,但使此列隐藏,当点任一行时调用此按钮产生的Javascript脚本。
Sub Item_Bound(ByVal sender As Object, ByVal e As DataGridItemEventArgs )
Dim itemType As ListItemType
itemType = CType(e.Item.ItemType, ListItemType)
If (itemType <> ListItemType.Header) And _
(itemType <> ListItemType.Footer) And _
(itemType <> ListItemType.Separator) Then
Dim oSelect As LinkButton = CType(e.Item.Cells(5).Controls(0), LinkButton)
e.Item.Attributes("onclick") = Page. GetPostBackClientHyperlink (oSelect, "")
End Sub
这里假设选择按钮位于第6列。e.Item代表了一行,从生成的HTML上看就是在每个<tr>里增加了一个onclick事件。Page.GetPostBackClientHyperLink方法返回页面中LinkButton控件产生的客户端脚本,其中第一个参数是Linkbutton控件,第二个参数是传递给此控件的参数,通常为空。如果不是LinkButton控件,有一个类似的函数GetPostBackClientEvent,读者可以参考MSDN。
● 服务器产生的脚本与手工添加的脚本冲突
服务器控件的服务器事件一般对应到客户端控件的相应事件,如Dropdownlist的SelectedIndexChanged事件对应HTML <Select>的onchange事件。如果你要手工增加一个onchange事件,则会在客户端产生两个onchange,浏览器就会忽略掉一个。比如用户希望每当改变了Dropdownlist中的选项就保存到数据库(虽然不是很常见,但确实有这种需要),但同时还希望提醒用户是否确实要做保存。显然,保存的代码应该放在SelectedIndexChanged事件中,而提醒的工作应该手工加一段onchange事件。结果就是两个onchange只能执行一个。正确的方法应该是添加一个不可见的保存按钮,在手工增加的onchange事件中调用此按钮生成的程序。
Page_Load方法如下:
Dim sCmd as string
sCmd=Page.GetPostBackClientHyperlink(btnUpdate, "")
If not page.isPostback then
Dropdownlist1.Attributes.add("onchange","ConfirmUpdate(""" & sCmd & """)")
End if
ConfirmUpdate函数如下
<Script language=”javascript”>
function ConfirmUpdate(cmd){
if confirm(“Are you sure to update?”)
eval(cmd);
}
</Script>
这里利用了Javascript eval函数来调用一个字符串中包含的命令。需注意的是包含命令的字符串不能用单引号括起来,因为自动生成的脚本中包括单引号,所以这里用两个双引号表示字符串本身的双引号。
三、结束语
以上简单讨论了在ASP.Net中插入Javascript的几种情况。合理地在服务器程序中插入客户端的Javascript脚本,可以提高程序的运行效率并提供更友好的用户界面。
因为近来想写个类似于远程桌面监控的程序,该程序中要用到屏幕捕捉.为实现该程序的一部分功能,做了个小DEMO.程序很简单,用到的技术也不多,只能实现类似qq的截图功能(方法虽然很笨)
程序流程如下:
1.截取整个屏幕并保存
2.新开一个全屏窗口,将保存的屏幕作为背景
3.鼠标拖动改变截取范围,右键取消
4.双击截取,保存在粘贴板,全屏窗口关闭
好了,下面的是代码部分
首先新建一个项目ScreenCutter(VS2005),将窗体名改为MainForm,再新建一个窗体ScreenBody.
添加一个按钮btnCutter到ScreenCutter并添加按钮事件:
private void btnCutter_Click(object sender, EventArgs e)
{
Image img = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);
Graphics g = Graphics.FromImage(img);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.AllScreens[0].Bounds.Size);
ScreenBody body = new ScreenBody();
body.BackgroundImage = img;
body.Show();
}Screen.AllScreens[0]是获取当前所有设备窗口的第一个,我这里只有一个显示器,当然我就是第一个.
利用Graphics的CopyFromScreen函数获取当前屏幕.
好了,现在按下按钮全屏窗口就会出来了.
下面讲全屏窗口ScreenBody,首先设置窗体的FormBorderStyle为None,然后声明以下变量
private Graphics MainPainter; //主画笔
private Pen pen; //就是笔咯
private bool isDowned; //判断鼠标是否按下
private bool RectReady; //矩形是否绘制完成
private Image baseImage; //基本图形(原来的画面)
private Rectangle Rect; //就是要保存的矩形
private Point downPoint; //鼠标按下的点
int tmpx;
int tmpy;
之后就是窗体的鼠标函数了,里面很多代码都没有作出整理,看了一下,整理后的代码应该会更少更精简的
private void ScreenBody_DoubleClick(object sender, EventArgs e)
{
if (((MouseEventArgs)e).Button == MouseButtons.Left &&Rect.Contains(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y))
{
//保存的时候有很多种方法的......我这里只用了这种
Image memory = new Bitmap(Rect.Width, Rect.Height);
Graphics g = Graphics.FromImage(memory);
g.CopyFromScreen(Rect.X 1, Rect.Y 1, 0, 0, Rect.Size);
Clipboard.SetImage(memory);
this.Close();
}
}
private void ScreenBody_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDowned = true;
if (RectReady == false)
{
Rect.X = e.X;
Rect.Y = e.Y;
downPoint = new Point(e.X, e.Y);
}
if (RectReady == true)
{
tmpx = e.X;
tmpy = e.Y;
}
}
if (e.Button == MouseButtons.Right)
{
if (RectReady != true)
{
this.Close();
return;
}
MainPainter.DrawImage(baseImage, 0, 0);
RectReady = false;
}
}
private void ScreenBody_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDowned = false;
RectReady = true;
}
}
private void ScreenBody_MouseMove(object sender, MouseEventArgs e)
{
if (RectReady == false)
{
if (isDowned == true)
{
Image New = DrawScreen((Image)baseImage.Clone(), e.X, e.Y);
MainPainter.DrawImage(New, 0, 0);
New.Dispose();
}
}
if (RectReady == true)
{
if (Rect.Contains(e.X, e.Y))
{
//this.Cursor = Cursors.Hand;
if (isDowned == true)
{
//和上一次的位置比较获取偏移量
Rect.X = Rect.X e.X - tmpx;
Rect.Y = Rect.Y e.Y - tmpy;
//记录现在的位置
tmpx = e.X;
tmpy = e.Y;
MoveRect((Image)baseImage.Clone(), Rect);
}
}
}
}
private void ScreenBody_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
MainPainter = this.CreateGraphics();
pen = new Pen(Brushes.Blue);
isDowned = false;
baseImage = this.BackgroundImage;
Rect = new Rectangle();
RectReady = false;
}
辅助函数
本来应该写更多的辅助函数的,将窗体响应函数里面的代码放到里面来,不过本人很懒,就这样将就了.呵呵
private void DrawRect(Graphics Painter, int Mouse_x, int Mouse_y)
{
int width = 0;
int heigth = 0;
if (Mouse_y < Rect.Y)
{
Rect.Y = Mouse_y;
heigth = downPoint.Y - Mouse_y;
}
else
{
heigth = Mouse_y - downPoint.Y;
}
if (Mouse_x < Rect.X)
{
Rect.X = Mouse_x;
width = downPoint.X - Mouse_x;
}
else
{
width = Mouse_x - downPoint.X;
}
Rect.Size = new Size(width, heigth);
Painter.DrawRectangle(pen, Rect);
}
private Image DrawScreen(Image back, int Mouse_x, int Mouse_y)
{
Graphics Painter = Graphics.FromImage(back);
DrawRect(Painter, Mouse_x, Mouse_y);
return back;
}
private void MoveRect(Image image, Rectangle Rect)
{
Graphics Painter = Graphics.FromImage(image);
Painter.DrawRectangle(pen, Rect.X, Rect.Y, Rect.Width, Rect.Height);
DrawRects(Painter);
MainPainter.DrawImage(image, 0, 0);
image.Dispose();
}
到这里,代码就算是写完了,运行
有一位网友问我Google会不会检查css。我在英文论坛上转了转,现在普遍的观点如下:
据GoogleGuy说Google现在对css和Javascript都能进行分析。有人认为Google分析css就是为了探测作弊的手法,因为css是作弊的重要手段。但是一般认为Google并不是每个页面都去分析css,而是随机选一小部分页面分析css。至于你的页面会不会被Google分析css,就要看运气了。总之现在利用css作弊是很危险的。
.input1{
font-family: verdana;background-color: #EEEEEE;border-bottom: #FFFFFF 1px solid;border-left: #CCCCCC 1px solid;border-right: #FFFFFF 1px solid;border-top: #CCCCCC 1px solid;font-size: 12px;
}
.input1-bor {
font-family:verdana;background-color:#F0F8FF;font-size: 12px;
border: 1px solid #333333;}
</style>
<table cellspacing=2 cellpadding=0 width=300 border=0>
<tr>
<td><font class="en1">姓名:</font> </td>
<td><input size=40 name=name class="input1" onblur="this.className='input1'" onfocus="this.className='input1-bor'">
</td>
</tr>
<tr>
<td><font class="en1">邮箱:</font></td>
<td><input size=40 name=email class="input1" onblur="this.className='input1'" onfocus="this.className='input1-bor'"></td>
</tr>
<tr>
<td><font class="en1">网址:</font> </td>
<td><input size=40 name=url class="input1" onblur="this.className='input1'" onfocus="this.className='input1-bor'">
</td>
</tr>
<tr>
<td><font class="en1">主题:</font> </td>
<td><input size=40 name=subject class="input1" onblur="this.className='input1'" onfocus="this.className='input1-bor'">
</td>
</tr>
<tr>
<td><font class="en1">内容: </font> </td>
<td><textarea name=message rows=5 cols=35 class="input1" onblur="this.className='input1'" onfocus="this.className='input1-bor'"></textarea></td></tr></table>
一、 引言
到目前为止,你可能已经了解了大量的ASP.NET 2.0新特征-母版页面,主题,提供者,等等……所有这样内容都相当精彩;但是,你是否了解到有关定制Web控件开发方面的重大变化?这正是我在本文中所想讨论的。如果你已经从事于控件开发,那么,我想本文所描述的ASP.NET 2.0中的新的改进特征会立即应用于你的控件开发中。
首先应该注意的是,你以前使用ASP.NET 1.1(或1.0)开发的所有Web控件在2.0版本下将继续良好运行-微软并没有破坏你的现有代码。在本文中,我将向你介绍的所有相关内容,包括许多新的令人激动的技术,所有这些你都可以添加到现有控件或在新的控件环境中使用。
【作者注】本文假定你对定制Web控件开发已经有一个基本了解。在本文中,我以一个增强版本的EmailContact控件为例对ASP.NET 2.0中的Web控件改进技术作全面探讨。
二、 改进
表格1描述了ASP.NET 2.0在定制Web控件开发方面所作的大部分的重大改进。在本系列文章中,我将对这些特征展开逐一讨论。
表格1:ASP.NET 2.0 Web控件改进功能。
| 改进 | 描述 |
| 新的基类 | ASP.NET 2.0中又引入了一些新的基类供你派生自己的控件。后面,我重点介绍一个控件-CompositeControl。 |
| ControlState | 这是我们所熟悉的ViewState的"嫡亲"。如今,ControlState中已经不再需要使用专门的方法进行状态管理;另一方面,当控件用户在一个站点(或页面)上关闭状态管理机制时,有助于使你避免出错。 |
| 灵敏标签 | 这是令Windows控件开发者相当兴奋的新功能!在本文中,我将向你展示如何在你自己的定制控件中加入这样的功能。 |
| 模板设计时刻编辑 | 在1.1版本中,要对控件模板添加设计时刻编辑能力是相当困难的。幸好,ASP.NET 2.0使得添加这个功能相当容易。在本系列文章的最后一部分中我将讨论这个问题。 |
| 自动格式化 | 这也是一个巨大的改进!在使用DataGrid控件时你可以从一个预定义格式的列表中选择既定格式。ASP.NET 2.0使得在你的自定义控件中加入这一功能也非常容易。 |
| Web资源 | 这是我十分喜欢的一个改进,因为我总是不时地开发与图像有关的一些控件。在ASP.NET 2.0中,现在你可以发布一个控件的DLL,而且不必再考虑别的什么内容。也就是说,现在,你能够把图像和其它资源嵌入到控件的DLL文件内。 |
三、 增强EmailContact Web控件
本文中的定制EmailContact Web控件(参考图1)允许在你的站点中加入一个"contact us"表单,它具有完整的电子邮件功能。在本文中,我将使用该功能增强这一控件。

图1.缺省状态下的EmailContact控件
四、 一个新的基类
以前,开发者都是从WebControl类派生他们的可视化Web控件。我之所以在此使用了"可视化"一词是因为,典型情况上,没有在浏览器中生成任何内容的控件都是派生自Control类。这一点并没有改变-你应该继续使用该Control类来派生任何这样的非可视化控件-它们执行不可见功能或在浏览器中生成除可视化HTML内容之外的任何其它内容。而且,在开发可视化Web控件时,你还应该继续使用WebControl类。然而,我们所开发的大多数复合控件都是为了利用现有控件的功能。在这种情况下,你应该总是从WebControl类进行派生,但是你还要记住另外一些有关细节-否则的话,有可能导致许多问题。
复合控件必须实现INamingContainer接口,并且需要包括在你的控件类中。这个接口能够确保在你的控件及其可以生成的整个控件层次中的所有的HTML标签中都具有唯一的标签命名。当你在单个页面上存在多个相同类型的复合控件的情况下,这是相当关键的。在这样的情况下,你需要确保任何生成的子元素都具有唯一的名称。忘记实现该接口能够导致各种问题的出现。
在ASP.NET 2.0以前,复合控件开发者还需要记住在一个控件的Render方法中调用EnsureChildControls。在我以前的文章中曾经向你介绍如何重载该Render方法并且在调用基类的Render方法前调用这个方法。要使控件在Visual Studio设计时刻正确生成这一步是必要的;否则,有可能带来许多不便。
上面两个步骤在复合控件开发中如此普遍,以致于许多开发者往往都会构建一个包括这两个细节的基类,然后从该基类下派生他们所有的新的复合控件。作为代替,ASP.NET 2.0提供了(更准确地说是"名字为")CompositeControl。借助于这个类来构建你的复合控件,你就不必再记住实现INamingContainer或从Render方法中执行一个EnsureChildControls调用了。
另外,还存在其它一些新的基类,例如用于数据绑定的控件等,在此不再赘述。
点击返回上页代码:
<form>
<p><input TYPE="button" VALUE="返回上一步" ONCLICK="history.back(-1)"></p>
</form>
弹出警告框代码:
<form>
<p><input TYPE="button" VALUE="弹出警告框" ONCLICK="AlertButton()"></p>
</form>
<script language="JavaScript"><!--
function AlertButton(){window.alert("要多多光临呀!");}
// --></script>
点击打开新窗口
<form>
<p><input TYPE="button" VALUE="打开新窗口" ONCLICK="NewWindow()"></p>
</form>
<script language="JavaScript"><!--
function NewWindow(){window.open("http://www.mcmx.com","","height=240,width=340,status=no,location=no,toolbar=no,directories=no,menubar=no");}
// --></script></body>
删除记录时弹出确认框:
<script LANGUAGE="VBSCRIPT">
a=msgbox("真的要删除该记录吗?",1,"注意")
if a=1 then
location="Dodelete.asp?id=<%=id%>" //指向执行删除的页面Dodelete.asp
else
history.go(-1)
end if
</script>
关闭打开的窗口
< a href="/" onclick="javascript:window.close(); return false;">关闭窗口</a>
清空INPUT且选定
onClick="Javascript:this.value=''" onFocus="this.select()" onMouseOver="this.focus()"
右键屏蔽
<body oncontextmenu=self.event.returnValue=false>
连串英文自动换行的解决方法 IE5.5
style="LEFT: 0px; WIDTH: 100%; WORD-WRAP: break-word" 你可修改为指定的大小如 200px
图片“重置”按钮
<script language="jscript">
function myreset()
{ document.login.reset();
document.login.focus();}
</script>
<img src="image/reclear.gif" width="69" height="20" style="cursor:hand" onfocus="this.blur()" onclick="myreset()"
画细线表格
<table style="border-collapse: collapse">
状态栏信息
<form>
<p><input TYPE="button" VALUE="状态栏信息" ONCLICK="StatusButton()"></p>
</form>
<script language="JavaScript"><!--
function StatusButton(){window.status="要多多光临呀!";}
// --></script>
最小化、最大化、关闭窗口
<object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">
<param name="Command" value="Minimize"></object>
<object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">
<param name="Command" value="Maximize"></object>
<OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11">
<PARAM NAME="Command" VALUE="Close"></OBJECT>
<input type=button value=最小化 onclick=hh1.Click()>
<input type=button value=最大化 onclick=hh2.Click()>
<input type=button value=关闭 onclick=hh3.Click()>
本例适用于IE
隐藏状态栏里出现的LINK信息
<a href="http://"; onMouseOver="window.status='none';return true">梦想天空</a>
文本框自动滚动条
<textarea name=words rows=18 cols=26 style="border:1 solid #000000;background-color:white; font-size:9pt; width:188; overflow:auto" wrap=hard></textarea>
全选并复制
<FORM name=test><INPUT onclick="javascript:HighlightAll('test.select1')" type=button value=全选并复制><BR><TEXTAREA name=select1 rows=3 cols=46>你好,欢迎您的光临!</TEXTAREA>
</FORM>
<SCRIPT language=Javascript>
<!--
var copytoclip=1
function HighlightAll(theField) {
var tempval=eval("document." theField)
tempval.focus()
tempval.select()
if (document.all&©toclip==1){
therange=tempval.createTextRange()
therange.execCommand("Copy")
window.status="Contents highlighted and copied to clipboard!"
setTimeout("window.status=''",1800)
}
}
//-->
</SCRIPT>
屏蔽JAVASCRIPT错误
<script language="JavaScript">
<!--
function killErrors(){
return true;
}
window.onerror = killErrors;
-->
</script>
关闭子窗口时刷新父窗口
<script language="JavaScript">
<!--
self.opener.location.reload();
window.close()
-->
</script>
背景色变换
<form>
<p><input TYPE="button" VALUE="背景色变换" onClick="BgButton()"></p>
</form>
<script>function BgButton(){
if (document.bgColor=='#00ffff')
{document.bgColor='#ffffff';}
else{document.bgColor='#00ffff';}
}
</script>
检查一段字符串是否全由数字组成
<script language="Javascript"><!--
function checkNum(str){return str.match(//D/)==null}
alert(checkNum("1232142141"))
alert(checkNum("123214214a1"))
// --></script>
判断是否是字符
if (/[^/x00-/xff]/g.test(s)) alert("含有汉字");
点击刷新代码:
<form>
<p><input TYPE="button" VALUE="刷新按钮一" ONCLICK="ReloadButton()"></p>
</form>
<script language="JavaScript"><!--
function ReloadButton(){location.href="allbutton.htm";}
// --></script>
让层不被控件复盖代码:
<div z-Index:2><object xxx></object></div> # 前面
<div z-Index:1><object xxx></object></div> # 后面
<div id="Layer2" style="position:absolute; top:40;width:400px; height:95px;z-index:2"><table height=100% width=100% bgcolor="#ff0000"><tr><td height=100% width=100%></td></tr></table><iframe width=0 height=0></iframe></div>
<div id="Layer1" style="position:absolute; top:50;width:200px; height:115px;z-index:1"><iframe height=100% width=100%></iframe></div>
让层的相对定位
<div id="Layer1" style="position:relative; left:0px; top:0px; width:0px; height:0px;z-index:1">
<div id="Layer2" style="position:absolute; left:500px; top:0px; width:220px; height:220px; z-index:1">
内容
</div></div>
Flash代码以及背景透明
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="200" height="200">
<param name="movie" value="文件">
<param name="quality" value="high">
<param name="wmode" value="transparent">
<embed src="images/fish.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="220" height="220"></embed></object>
Windows Media Player 播放器
<OBJECT id=MediaPlayer1
style="LEFT: 0px; VISIBILITY: visible; POSITION: absolute; TOP: 0px;z-index:2"
codeBase=http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701standby=
Loading
type=application/x-oleobject height=300 width=320
classid=CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6 VIEWASTEXT>
<PARAM NAME="URL" VALUE="地址">
<param name="AudioStream" value="-1">
<param name="AutoSize" value="0">
<param name="AutoStart" value="-1">
<param name="AnimationAtStart" value="0">
<param name="AllowScan" value="-1">
<param name="AllowChangeDisplaySize" value="-1">
<param name="AutoRewind" value="0">
<param name="Balance" value="0">
<param name="BaseURL" value>
<param name="BufferingTime" value="5">
<param name="CaptioningID" value>
<param name="ClickToPlay" value="-1">
<param name="CursorType" value="0">
<param name="CurrentPosition" value="-1">
<param name="CurrentMarker" value="0">
<param name="DefaultFrame" value>
<param name="DisplayBackColor" value="0">
<param name="DisplayForeColor" value="16777215">
<param name="DisplayMode" value="0">
<param name="DisplaySize" value="4">
<param name="Enabled" value="-1">
<param name="EnableContextMenu" value="-1">
<param name="EnablePositionControls" value="0">
<param name="EnableFullScreenControls" value="0">
<param name="EnableTracker" value="-1">
<param name="InvokeURLs" value="-1">
<param name="Language" value="-1">
<param name="Mute" value="0">
<param name="PlayCount" value="1">
<param name="PreviewMode" value="0">
<param name="Rate" value="1">
<param name="SAMILang" value>
<param name="SAMIStyle" value>
<param name="SAMIFileName" value>
<param name="SelectionStart" value="-1">
<param name="SelectionEnd" value="-1">
<param name="SendOpenStateChangeEvents" value="-1">
<param name="SendWarningEvents" value="-1">
<param name="SendErrorEvents" value="-1">
<param name="SendKeyboardEvents" value="0">
<param name="SendMouseClickEvents" value="0">
<param name="SendMouseMoveEvents" value="0">
<param name="SendPlayStateChangeEvents" value="-1">
<param name="ShowCaptioning" value="0">
<param name="ShowControls" value="-1">
<param name="ShowAudioControls" value="-1">
<param name="ShowDisplay" value="0">
<param name="ShowGotoBar" value="0">
<param name="ShowPositionControls" value="-1">
<param name="ShowStatusBar" value="-1">
<param name="ShowTracker" value="-1">
<param name="TransparentAtStart" value="-1">
<param name="VideoBorderWidth" value="0">
<param name="VideoBorderColor" value="0">
<param name="VideoBorder3D" value="0">
<param name="Volume" value="70">
<param name="WindowlessVideo" value="0">
</OBJECT>
RealPlayer 播放器
<object id=video1 classid=" clasid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA"
width=320 height=240 align="middle">
<param name="controls" value="inagewindow">
<param name="console" value="chicp1">
<param name="autostar" value="true">
<param name="src" value="地址">
<embed
src="地址"
type="audio/x-pn-realaudio-plugin" console="chip1"
controls="imagewindow" width=320 height=240 autostart=true align="middle">
</embed>
</object>
SqlDataSource控件的DataSourceMode属性决定所提取的数据要如何维护。
DataSourceMode属性的默认值是DataSet,此表示从数据库提取而来的结果集会储存在服务器内存内的一个DataSet对象中,如果您使用SqlDataSource作为GridView等控件的数据来源,并且要在GridView控件中进行排序、筛选与分页等处理,则SqlDataSource的DataSourceMode属性一定要设定成DataSet。
然而在另外一方面,如果SqlDataSource所提取的数据仅仅是要作为DropDownList与ListBox等控件的选项,而不需要进行排序、筛选与分页等处理,则SqlDataSource的DataSourceMode属性应该要设定成DataReader,如此才能降低资源的耗用。毕竟在这种时候使用数据集(DataSet)根本就是杀鸡用牛刀。
一旦您将DataSourceMode属性设定成DataReader,数据会通过一个IDataReader对象(亦即顺向且只读的数据指针)来提取,结果集将不会储存在服务器的内存中。
如果您对数据集模型与数据命令模型的特色与差异有清楚的认识,相信应该可以知道何时该使用DataSet,而何时又该使用DataReader。
最简格式:这是一个偷巧的方法,但不通用。前提是这个页面只有一个datagrid,且只有datagrid中有checkbox;这个就比较方便。主要思路就是搜索出整个页面的checkbox,将它们全部选中或反选。
// 全选
function allCheck()
{
for (var i=0;i<Form1.elements.length;i )
{
var e=Form1.elements[i];
if (e.type=='checkbox')
e.checked=true;
}
}
//反选
function revCheck()
{
for (var i=0;i<Form1.elements.length;i )
{
var e=Form1.elements[i];
if (e.type=='checkbox')
e.checked=!e.checked;
}
}
通用简单格式
因为asp.net页面中生成datagrid中的checkbox,他的ID是要改变的,所以我们寻找它们的规律,就可以准确的找到这个控件,从而进行全选和反选及选中的操作,
参数说明:
prefix:前缀;s:选择框ID;chk:选择框的ID;
function getObj( objID )
{
return document.getElementById( objID );
}
// 全选
function _SelectAll( prefix,s,chk )
{
var oArr = _GetColl( prefix,s,chk );
for( var o in oArr )
{
oArr[o].checked = true;
}
}
// 反选
function _RevSelect( prefix,s,chk )
{
var oArr = _GetColl( prefix,s,chk );
for( var o in oArr )
{
oArr[o].checked = !oArr[o].checked;
}
}
// 获值
function _GetColl( prefix,s,chk )
{
var i = s;
var oArr = new Array();
while( true)
{
var o = getObj( prefix '__ctl' i '_' chk);
if( o != null )
{
oArr.push( o );
}
else
{
break;
}
i ;
}
return oArr;
}
// 检查是否选中
function _CheckSelect( prefix,s,chk )
{
var oArr = _GetColl( prefix,s,chk );
for( var o in oArr )
{
if( oArr[o].checked)
{
return true;
}
}
return false;
}
推荐通用详细格式:http://www.cnblogs.com/ghd258/archive/2005/11/07/270449.html#Post
/* 分页
2 参数说明:
3 prefix:前缀;chkAll:全选框;chkSingle:单选框ID
4
5 使用方法:
6 if(e.Item.ItemType == ListItemType.Header)
7 {
8 ((CheckBox)e.Item.Cells[1].FindControl("chkAll")).Attributes.Add("onclick","CheckAll('" this.dg.ClientID.ToString() "','chkAll','chkSingle');");
9 }
10*/
11function CheckAll(prefix,chkAll,chkSingle)
12{
13 var indexChkAll;
14 if(prefix.length != 0)
15 {
16 indexChkAll = prefix "__ctl2_" chkAll;
17 }
18 else
19 {
20 indexChkAll = chkAll;
21 }
22 var objChkAll = document.getElementById(indexChkAll);
23 var tempObj;
24 for(var i=0;i<document.forms[0].elements.length;i )
25 {
26 tempObj = document.forms[0].elements[i];
27 if(tempObj.type == "checkbox" && tempObj.id != indexChkAll && tempObj.id.indexOf(chkSingle) != -1)
28 {
29 tempObj.checked = objChkAll.checked;
30 }
31 }
32}
33/**//* 分页
34 参数说明:
35 prefix:前缀;chkAll:全选框;chkSingle:单选框ID
36
37 使用方法:
38 if(e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
39 {
40 ((CheckBox)e.Item.Cells[1].FindControl("chkSingle")).Attributes.Add("onclick","CheckSingle('" this.dg.ClientID.ToString() "','chkAll','chkSingle');");
41 }
42*/
43function CheckSingle(prefix,chkAll,chkSingle)
44{
45 var indexChkAll;
46 if(prefix.length != 0)
47 {
48 indexChkAll = prefix "__ctl2_" chkAll;
49 }
50 else
51 {
52 indexChkAll = chkAll;
53 }
54 var objChkAll = document.getElementById(indexChkAll);
55 var tempObj;
56 var allCount = 0;
57 var checkCount = 0;
58 for(var i=0;i<document.forms[0].elements.length;i )
59 {
60 tempObj = document.forms[0].elements[i];
61 if(tempObj.type == "checkbox" && tempObj.id != indexChkAll && tempObj.id.indexOf(chkSingle) != -1)
62 {
63 if(tempObj.checked)
64 {
65 checkCount ;
66 }
67 else
68 {
69 objChkAll.checked = false;
70 //break;
71 }
72 allCount ;
73 }
74 }
75 if(checkCount != allCount)
76 {
77 objChkAll.checked = false;
78 }
79 else
80 {
81 if(allCount != 0)
82 {
83 objChkAll.checked = true;
84 }
85 }
86}
87/**//*
88 参数说明:
89 prefix:前缀;chkAll:全选框;chkSingle:单选框ID
90 type:1【全选】,2【反选】,3【取消】
91
92 使用方法:
93 this.btnSelectAll.Attributes.Add("onClick","CheckType('" this.dg.ClientID.ToString() "','chkAll','chkSingle',1);");
94 this.btnUnSelectAll.Attributes.Add("onClick","CheckType('" this.dg.ClientID.ToString() "','chkAll','chkSingle',2);");
95 this.btnCancelSelect.Attributes.Add("onClick","CheckType('" this.dg.ClientID.ToString() "','chkAll','chkSingle',3);");
96*/
97function CheckType(prefix,chkAll,chkSingle,type)
98{
99 var indexChkAll;
100 if(prefix.length != 0)
101 {
102 indexChkAll = prefix "__ctl2_" chkAll;
103 }
104 else
105 {
106 indexChkAll = chkAll;
107 }
108 var objChkAll = document.getElementById(indexChkAll);
109 var tempObj;
110 var allCount = 0;
111 var checkCount = 0;
112 for(var i=0;i<document.forms[0].elements.length;i )
113 {
114 tempObj = document.forms[0].elements[i];
115 if(tempObj.type == "checkbox" && tempObj.id != indexChkAll && tempObj.id.indexOf(chkSingle) != -1)
116 {
117 switch(type)
118 {
119 case 1:
120 tempObj.checked = true;
121 break;
122 case 2:
123 tempObj.checked = !tempObj.checked;
124 break;
125 case 3:
126 tempObj.checked = false;
127 break;
128 }
129 if(tempObj.checked)
130 {
131 checkCount ;
132 }
133 allCount ;
134 }
135 }
136 if(checkCount != allCount)
137 {
138 objChkAll.checked = false;
139 }
140 else
141 {
142 if(allCount != 0)
143 {
144 objChkAll.checked = true;
145 }
146 }
147 window.event.returnValue = false;
148 return false;
149}
150
151/**//*
152 参数说明:
153 prefix:前缀;chkAll:全选框;chkSingle:单选框ID
154
155 使用方法:
156 this.btnDelete.Attributes.Add("onClick","SubmitCheckBox('" this.dg.ClientID.ToString() "','chkAll','chkSingle');");
157*/
158function SubmitCheckBox(prefix,chkAll,chkSingle,msg)
159{
160 var indexChkAll;
161 if(prefix.length != 0)
162 {
163 indexChkAll = prefix "__ctl2_" chkAll;
164 }
165 else
166 {
167 indexChkAll = chkAll;
168 }
169 var objChkAll = document.getElementById(indexChkAll);
170
171 var tempObj;
172 var allCount = 0;
173 var checkCount = 0;
174 for(var i=0;i<document.forms[0].elements.length;i )
175 {
176 tempObj = document.forms[0].elements[i];
177 if(tempObj.type == "checkbox" && tempObj.id != indexChkAll && tempObj.id.indexOf(chkSingle) != -1)
178 {
179 if(tempObj.checked)
180 {
181 checkCount ;
182 }
183 allCount ;
184 }
185 }
186 if(allCount == 0) //没有数据
187 {
188 window.alert("当前没有" msg "可供删除");
189 window.event.returnValue = false;
190 return false;
191 }
192 else
193 {
194 if(checkCount == 0)
195 {
196 window.alert("没有选中要删除的" msg "");
197 window.event.returnValue = false;
198 return false;
199 }
200 else
201 {
202 //if(window.confirm("确定要删除当前选中的【" checkCount.toString() "】项吗?") == false)
203 if(window.confirm("确定要删除当前选中的" msg "吗?") == false)
204 {
205 window.event.returnValue = false;
206 return false;
207 }
208 }
209 }
210}
var singlepost=false;
var firstpost;
var anchor;
for(var i=0;i<main.childNodes.length;i )
{
if(main.childNodes[i].className&&main.childNodes[i].className=="post")
{
var post=main.childNodes[i];
if(!firstpost)
{
firstpost=post;
}
for(var j=0;j<post.childNodes.length;j )
{
if(post.childNodes[j].className&&post.childNodes[j].className=="posthead")
{
var posthead=post.childNodes[j];
if(posthead.childNodes[1]&&posthead.childNodes[1].tagName&&posthead.childNodes[1].tagName=="H2")
{
if(posthead.childNodes[1].childNodes[1]&&posthead.childNodes[1].childNodes[1].tagName&&posthead.childNodes[1].childNodes[1].tagName=="A")
{
anchor=posthead.childNodes[1].childNodes[1];
}
else
{
anchor=posthead.childNodes[1].childNodes[0];
}
}
else
{
anchor=posthead.childNodes[0].childNodes[0];
}
anchor.style.fontSize="14pt";
if(anchor.className&&anchor.className=="singleposttitle")
{
singlepost=true;
}
}
}
}
}
if(singlepost)
{
var postfoot=document.createElement("div");
firstpost.appendChild(postfoot);
postfoot.className="postfoot";
postfoot.innerHTML="<a href=\"http://del.icio.us/post?v=4&url=" encodeURIComponent(location.href) "&title=" encodeURIComponent(document.title) "\"><img src=\http://del.icio.us/favicon.ico\ alt=\"Add to del.icio.us\" border=\"0\"/><span>Add to del.icio.us</span></a>";
postfoot.innerHTML ="<a href=\"http://digg.com/submit?phase=2&url=" encodeURIComponent(location.href) "&title=" encodeURIComponent(document.title) "\"><img src=\http://digg.com/favicon.ico\ alt=\"Digg This!\" border=\"0\"/><span>Digg This!</span></a>";
postfoot.innerHTML ="<a href=\"http://www.facebook.com/share.php?u=" encodeURIComponent(location.href) "\"><img src=\http://www.facebook.com/favicon.ico\ alt=\"Share on Facebook\" border=\"0\"/><span>Share on Facebook</span></a>";
postfoot.innerHTML ="<a href=\"http://www.google.com/bookmarks/mark?op=edit&bkmk=" encodeURIComponent(location.href) "&title=" encodeURIComponent(document.title) "\"><img src=\http://www.google.com/favicon.ico\ alt=\"Google Bookmark This\" border=\"0\"/><span>Google Bookmark This</span></a>";
}
前两天发完《SEO参考:DIV CSS三行两列经典布局》一文,不少朋友在MSN上问我,使用XHTML标准的DIV CSS布局对于SEO到底有什么作用。这两天简单总结了一下,写出来供参考。
XHTML技术问题请参考相关网站研究,下面说说在SEO方面的影响。
代码精简
使用DIV CSS布局,页面代码精简,这一点相信对XHTML有所了解的都知道。代码精简所带来的直接好处有两点:一是提高spider爬行效率,能在最短的时间内爬完整个页面,这样对收录质量有一定好处;二是由于能高效的爬行,就会受到spider喜欢,这样对收录数量有一定好处。
表格的嵌套问题
很多SEOer在其文章中称,搜索引擎一般不抓取三层以上的表格嵌套,这一点一直没有得到搜索引擎官方的证实。我的几项实验结果没有完全出来,但根据目前掌握的情况来看,spider爬行Table布局的页面,遇到多层表格嵌套时,会跳过嵌套的内容或直接放弃整个页面。
使用Table布局,为了达到一定的视觉效果,不得不套用多个表格。如果嵌套的表格中是核心内容,spider爬行时跳过了这一段没有抓取到页面的核心,这个页面就成了相似页面。网站中过多的相似页面会影响排名及域名信任度。
而DIV CSS布局基本上不会存在这样的问题,从技术角度来说,XHTML在控制样式时也不需要过多的嵌套。
这虽然没有得到确认,但还是建议使用Table布局的朋友们,在设计时尽可能的不要使用多层表格嵌套,SEOer们在文章中说明了这一点,相信他们也不是没有依据的。
速度问题
DIV CSS布局较Table布局减少了页面代码,加载速度得到很大的提高,这在spider爬行时是非常有利的。过多的页面代码可能造成爬行超时,spider就会认为这个页面无法访问,影响收录及权重。
另一方面,真正的SEOer不只是为了追求收录、排名,快速的响应速度是提高用户体验度的基础,这对整个搜索引擎优化及营销都是非常有利的。
对排名的影响
基于XTHML标准的DIV CSS布局,一般在设计完成后会尽可能的完善到能通过W3C验证。截止目前没有搜索引擎表示排名规则会倾向于符合W3C标准的网站或页面,但事实证明使用XTHML架构的网站排名状况一般都不错。这一点或许会有争议,但樂思蜀本人保持这样的观点,有异议者可以拿三组以上基本同等质量的网站对比观察。
我想,这样的情况可能不是排名规则,最大的可能还是spider爬行网站时,出现以上差异导致收录质量的不同。
毕竟廖胜于无,建议建站或改版的朋友们,技术许可的情况下,还是选择DIV CSS布局为好。
<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<html lang="us-en">
<head>
<title>css选项卡(html组件)</title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<meta http-equiv="content-type" content="text/html; charset=gb2312" />
<meta name="keywords" content=" "/>
<meta name="description" content="" />
<style type="text/css">
div.card div{ background-color:#FF8000; float:left; padding:1px; padding-bottom:0; clear:both; width:405px;}
div.card a{ color:black; font-size:14px; text-decoration:none; float:left; width:100px; text-align:center; background-color:white; margin-right:1px;}
div.card div.home a.home{ font:normal normal bold 14px/1.5 宋体;}
div.card div.international a.international { font:normal normal bold 14px/1.5 宋体;}
div.card div.sport a.sport{ font:normal normal bold 14px/1.5 宋体;}
div.card div.finance a.finance{ font:normal normal bold 14px/1.5 宋体;}
div.card div.content{ background-color:white; border:1px solid #ff8000; height:100px;}
</style>
<script type="text/javascript">
var shq={}
shq.cmenu=function(e)
{
var e=window.event?window.event.srcElement:e.target;
if(/a/i.test(e.tagName)){
e.parentNode.className=e.className;
e.parentNode.nextSibling.innerHTML=e.innerHTML;
e.parentNode.nextSibling.style.cssText='border-top:none';
e.blur();
}
}
</script>
</head>
<body>
<div class="card">
<div onclick="shq.cmenu(event)">
<a href="#" class="home">国内</a>
<a href="#" class="international">国际</a>
<a href="#" class="sport">体育</a>
<a href="#" class="finance">财经</a>
</div><div class="content"></div>
</div>
<div class="card">
<div onclick="shq.cmenu(event)">
<a href="#" class="home">国内</a>
<a href="#" class="international">国际</a>
<a href="#" class="sport">体育</a>
<a href="#" class="finance">财经</a>
</div><div class="content"></div>
</div>
<div class="card">
<div onclick="shq.cmenu(event)">
<a href="#" class="home">国内</a>
<a href="#" class="international">国际</a>
<a href="#" class="sport">体育</a>
<a href="#" class="finance">财经</a>
</div><div class="content"></div>
</div>
</body>
</html>






