针对有网友说看不见文章内容, 现提示如下: 点击每一个标题行任一地方都会展开和隐藏此文章内容(不要点击标题). 目前展开隐藏功能只支持IE浏览器,虽然可以改成支持FF浏览器,不过现在一直没时间去弄,等有时间再修改了。 |
blog名称:乱闪Blog 日志总数:267 评论数量:1618 留言数量:-26 访问次数:2675537 建立时间:2005年1月1日 |
|

| |
Global.asa使用手册
|
来源: 未知
作者: great_domino
更新日期: [2005-03-12]
Global.asa 文件是一个可选文件,用户可以在该文件中指定事件脚本,并声明具有会话和应用程序作用域的对象。该文件的内容 给用户显示的,而是用来存储事件信息和由应用程序全局使用的对象。该文件的名称必须是 Global.asa 且必须存放在应用程序的 根目录中。每个应用程序只能有一个 Global.asa 文件。
Global.asa 文件只能包含如下内容:
1.应用程序事件
2.会话事件
3.<OBJECT> 声明
TypeLibrary 声明 如果包含的脚本没有用 <SCRIPT> 标记封装,或定义的对象没有会话或应用程序作用域,则服务器将返回错误。服务器会忽略已标 记的但未被应用程序或会话事件使用的脚本以及文件中的 HTML 语句。
可以用任何支持脚本的语言编写 Global.asa 文件中包含的脚本。如果多个事件使用同一种脚本语言,就可以将它们组织在一组 <SCRIPT> 标记中。
当用户保存对 Global.asa 文件所做的更改时,在重新编译 Global.asa 文件之前,服务器会结束处理当前应用程序的所有请 求。在此期间,服务器拒绝其他请求并返回一个错误消息,说明正在重启动应用程序,不能处理请求。
当用户当前的所有请求处理完之后,服务器对每个会话调用 Session_OnEnd 事件,删除所有活动会话,并调用 Application_OnEnd 事件关闭应用程序,然后编译 Global.asa 文件。接下来,用户的请求将启动应用程序并创建新的会话,触 发 Application_OnStart 和 Session_OnStart 事件。
但是,保存 Global.asa 文件中所包含的文件的更改并不能使服务器重新编译 Global.asa。为了让服务器识别包含文件的改动, 必须再保存一下 Global.asa 文件。
在 Global.asa 文件中声明的过程只能从一个或多个与 Application_OnStart、Application_OnEnd、Session_OnStart 和 Session_OnEnd 事件相关的脚本中调用。在基于 ASP 的应用程序中的 ASP 页中,它们是不可用的。
要在应用程序之间共享过程,可在单独的文件中声明这些过程,然后使用服务器端的包含 (SSI) 语句将该文件包含在调用该过程 的 ASP 页中。通常,包含文件的扩展名应为 .inc。
基于 ASP 的应用程序由在其根目录及其子目录中所有文件组成。应用程序在用户首次打开应用程序中的某一 Web 页时启动,在服 务器关闭时终止。应用程序有两个事件,即 Application_OnStart 事件和 Application_OnEnd 事件。
用户可以在 Global.asa 文件中为这些事件指定脚本。当应用程序启动时,服务器在 Global.asa 文件中查找并处理 Application_OnStart 事件脚本。当应用程序终止时,服务器处理 Application_OnEnd 事件脚本。
1.Application_OnStart Application_OnStart 事件在首次创建新的会话(即 Session_OnStart 事件)之前发生。只有 Application 和 Server 内建 对象是可用的。在 Application_OnStart 事件脚本中引用 Session、Request 或 Response 对象将导致错误。
语法 <SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server> Sub Application_OnStart. . . End Sub
</SCRIPT>
参数 ScriptLanguage 指定用于编写事件脚本的脚本语言。它可以是任何支持脚本编写的语言,例如 VB Script 或 JScript。如果多个事件使用同一种 脚本语言,就可以将它们组织在一个 <SCRIPT> 标记下。
2.Application_OnEnd Application_OnEnd 事件在应用程序退出时于 Session_OnEnd 事件之后发生,只有 Application 和 Server 内建对象可用。
语法 <SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server> Sub Application_OnEnd. . . End Sub
</SCRIPT>
参数 ScriptLanguage 指定用于编写事件脚本的脚本编写语言。可以是任何一种支持脚本的语言,例如 VBScript 或 JScript。如果有多个事件使用同 一种脚本编写语言,就可以将它们组织在一组 <SCRIPT> 标记下。 注释 不能在 Application_OnEnd 脚本中调用 MapPath 方法。
当没有会话的用户在打开应用程序中的 Web 页时,Web 服务器会自动创建会话。当超时或服务器调用 Abandon 方法时,服务器 将终止该会话。
会话有两个事件,即 Session_OnStart 事件和 Session_OnEnd 事件。
可以在全局文件 Global.asa 中为这两个事件指定脚本。当会话开始时,服务器在 Global.asa 文件中查找并处理 Session_OnStart 事件脚本。该脚本将在处理用户请求的 Web 页之前处理。在会话结束时,服务器将处理 Session_OnEnd 事件 脚本。
1.Session_OnStart Session_OnStart 事件在服务器创建新会话时发生。服务器在执行请求的页之前先处理该脚本。Session_OnStart 事件是设置会 话期变量的最佳时机,因为在访问任何页之前都会先设置它们。所有内建对象 (Application、ObjectContext、Request、 Response、Server 和 Session) 都可以在 Session_OnStart 事件脚本中使用和引用。
语法 <SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server> Sub Session_OnStart. . .End Sub
</SCRIPT>
参数 ScriptLanguage 指定用于编写事件脚本的脚本编写语言。可以是任何一种支持脚本的语言,例如 VBScript 或 JScript。如果有多个事件使用同 一种脚本编写语言,就可以将它们组织在一组 <SCRIPT> 标记下。 示例 尽管在 Session_OnStart 事件包含 Redirect 或 End 方法调用的情况下 Session 对象仍会保持,然而服务器将停止处理 Global.asa 文件并触发 Session_OnStart 事件的文件中的脚本。
举一个例子,为了确保用户在打开某个特定的 Web 页时始终启动一个会话,就可以在 Session_OnStart 事件中调用 Redirect 方法。当用户进入应用程序时,服务器将为用户创建一个会话并处理 Session_OnStart 事件脚本。您可以将脚本包含在该事件中 以便检查用户打开的页是不是启动页,如果不是,就指示用户调用 Response.Redirect 方法启动网页。其演示如下例所示。
<SCRIPT RUNAT=Server Language=VBScript> Sub Session_OnStart ' Make sure that new users start on the correct ' page of the ASP application.
' Replace the value given to startPage below ' with the virtual path to your application's ' start page.
startPage = "/MyApp/StartHere.asp" currentPage = Request.ServerVariables("SCRIPT_NAME")
' Do a case-insensitive compare, and if they ' don't match, send the user to the start page. if strcomp(currentPage,startPage,1) then Response.Redirect(startPage) end ifEnd Sub</SCRIPT> 上述示例只能在支持 cookie 的浏览器中运行。因为不支持 cookie 的浏览器不能返回 SessionID cookie,所以,每当用户请 求 Web 页时,服务器都会创建一个新会话。这样,对于每个请求,服务器都将处理 Session_OnStart 脚本并将用户重定向到启 动页中。如果您要使用下面的脚本,建议您在启动页上放一个通知,告诉用户该站点要求支持 cookie 的浏览器。
注释 请注意,在 Redirect 方法之后的任何 Session_OnStart 事件脚本都不会执行。因此,应该在您的事件脚本的最后再调用 Redirect 方法。其演示如下例所示。
<SCRIPT LANGUAGE=VBScript RUNAT=Server> Sub Session_OnStart ' Session initialization script Response.Redirect "http:/server/app/StartHere.asp" End sub </SCRIPT> 在上面的例子中,Redirect 方法在执行会话初始化脚本期间隐藏所有显示给客户的文字。
2.Session_OnEnd Session_OnEnd 事件在会话被放弃或超时发生。在服务器内建对象中,只有 Application、Server 和 Session 对象可用。
语法 <SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server> Sub Session_OnEnd. . . End Sub
</SCRIPT>
参数 ScriptLanguage 指定用于编写事件脚本的脚本编写语言。可以是任一支持脚本编写的语言,例如 VBScript 或 JScript。如果有多个事件使用同 一种脚本编写语言,则可以将其组织在一组 <SCRIPT> 标记下。 注释 在 Session_OnEnd 脚本中不能调用 MapPath 方法。
<OBJECT> 声明 用户可以在 global.asa 文件中通过使用扩展的 <OBJECT> 标记创建带有会话或应用程序作用域的对象。该标记是自包含的,且 在任何 <SCRIPT> 标记之外。
在 Global.asa 文件中声明的对象在服务器处理调用该对象之前是不会创建的。这样就只会创建必需的对象,从而节约了资源。
服务器对带有应用程序作用域参数创建的对象不调用 OnStartPage 和 OnEndPage 方法。
语法 <OBJECT RUNAT=Server SCOPE=Scope ID=Identifier {PROGID="progID"¦CLASSID="ClassID"}>. . .
</OBJECT>
参数 Scope 指定对象的作用域。在 Global.asa 文件中,Scope 将被设置为 Session 或 Application。
Identifier 指定对象实例的名称。
ProgID 与类标识相关的标识。无论 ProgID 还是 ClassID 都必须在 <OBJECT> 中指定。ProgID 的格式为 [Vendor.]Component [.Version]。
ClassID 指定 COM 类对象的唯一标识。 无论 ProgID 还是 ClassID 都必须在 <OBJECT> 中指定。 示例 下面的第一个示例使用 ProgID 参数创建一个对象,其会话作用域名为 MyConnection。第二个示例使用 ClassID 参数。
<OBJECT RUNAT=Server SCOPE=Session ID=MyConnection PROGID="ADODB.Connection"> REM Object Script </OBJECT>
<OBJECT RUNAT=Server SCOPE=Session ID=MyConnection CLASSID="Clsid:8AD3067A-B3FC-11CF-A560-00A0C9081C21"> REM Object Script </OBJECT>
注释 在 Global.asa 文件中声明的对象可被应用程序中的任何脚本使用。例如,在声明了下列对象的情况下。
---GLOBAL.ASA--- <OBJECT RUNAT=Server SCOPE=Session ID=MyAd PROGID="MSWC.AdRotator"> </OBJECT>
可以从应用程序中的任何一页引用 MyAd 对象:
---SOME.ASP--- <%= MyAd.GetAdvertisement("/ads/adrot.txt") %>
TypeLibrary 声明
ActiveX 组件常常要描述类型库中该组件支持的常量。类型库是一个文件,其中包含有关 ActiveX 组件所支持的对象和类型的信 息。如果用户的 Web 应用程序依赖于已在类型库中声明了类型的 ActiveX 对象,就可以在 Global.asa 文件中声明其类型。这 样做以后,就可以在应用程序范围内从任何脚本引用已在类型库中声明了的数据类型。
有关在 ASP 中使用常量的详细信息,请参阅“使用变量和常量”。
语法 <!--METADATA TYPE="TypeLib" FILE="file" UUID="typelibraryuuid" VERSION="majorversionnumber.minorversionnumber" LCID="localeid" --> 参数 file 类型库的绝对路径。如果提供了该参数和 typelibraryuuid 参数,则 file 将用于标识类型库。file 参数和 typelibraryuuid 参数都是必选项。
typelibraryuuid 类型库统一的唯一标识。file 参数和 typelibraryuuid 参数都是必选项。
majorversionnumber 用于选择版本。如果找不到所需的版本,将返回错误。该参数是可选项。
minorversionnumber 用于选择版本。如果找不到所需的版本,将返回错误。该参数是可选项。
localeid 现场标识,用于类型库。如果找不到所需的现场,将返回错误。该参数是可选项。 错误信息 服务器可返回下列错误消息。
错误 说明 ASP 0222 指定的类型库无效。METADATA 标记包含无效的类型库指定。 ASP 0223 找不到类型库。METADATA 包含的类型库指定与注册表项不符。 ASP 0224 类型库无法加载。ASP 无法加载 METADATA 标记中指定的类型库。 ASP 0225 类型库不能重叠。ASP 无法从在 METADATA 标记中指定的类型库中创建 Type Library Wrapper 对象。
注释 最好将 METADATA 标记写在 Global.asa 文件的开始位置。但是,无论是内部和外部 SCRIPT 标记,都可以出现在 Global.asa 文件中的任何位置。
通过将类型库的名称加在该常量的前面,可以避免对常量的不明确引用。例如,ADODB.adErrItemNotFound 会比 adErrItemNotFound 更明确。
如果使用 Microsoft Visual InterDev 创建 global.asa 文件,则 METADATA 标记将包含可选的 STARTSPAN 和 ENDSPAN 关 键字。而 IIS 则会忽略这两个关键字。
示例 下面示例中的 MyComponent 是用 Visual Basic 5.0 编写的。MyComponent 使用下列语句定义常量 MyError。
Public Const MyError = "You are not using MyComponent correctly."
类型库包含在 mycomponent.lib 中,该文件安装在下面的目录中。
C:\MyComponent
下面的 METADATA 标记包含在 MyApp 应用程序的 global.asa 文件中。该示例使用可选的 STARTSPAN 和 ENDSPAN 标记。而 IIS 则不需要这两个标记。
<!--METADATA TYPE="TypeLib" FILE="MyComponent.lib" -->
现在,MyApp 应用程序中的任何 ASP 都包含如下脚本:
<% Dim MyVar Set MyVar = Server.CreateObject("MyComponent.MyClass") Currentreturn = MyVar.MyMethod If Currentreturn = False Response.Write(MyError) End If %>
|
|
自动适应输入内容高度的TextBox控件(摘自罗永浩全集)
|
来源: 未知
作者: cmoremore
更新日期: [2005-03-12]
关于Web开发上面UI布局的问题,我上次介绍了一个可以自动适应输入内容宽度的TextBox控件,它可以解决在布局时预留控件大小和用户数入内容多少上的矛盾。但是由于那个控件被限制了只能做为单行输入使用:(,在输入大块文本时就力不从心了,那么就再做一个可自动适应高度的TextBox。
原理和那个适应宽度的TextBox查不多,只是这个反而更加简单,因为在高度方向上增长不会破坏页面的整体布局效果(宽度上的如果在页内会挤走别的元素的),所以就不需要使用Agent TextBox来作为实际录入的容器了,直接把<TextArea>增高就行了。
响应onpropertychange事件,同步内容和<TextArea>的高度。当然如果完全根据内容增高可能也会因为内容太多而变得难看,就设置了一个最大高度限制属性。控件效果如下:
最大高度为200px的AutoTextBox Demo: 200)?200:this.scrollHeight)+(this.offsetHeight-this.clientHeight+1)" name=ataRemark rows=1 cols=1>
最大高度为200px但初始高度为3rows的AutoTextBox Demo: 200)?200:Math.max(this.minHeight,this.scrollHeight))+(this.offsetHeight-this.clientHeight)" name=ataRemark rows=3 minheight="63">
高度增长无限制的AutoTextBox Demo: 如果控件的MaxHeight属性小于或等于0,那么增长高度无限制。
附 AutoTextBox 控件源码
|
|
ASP中一个字符串处理类加强版
|
来源: 未知
作者: liuhuidev
更新日期: [2005-03-12]
以下是源代码:
<% class StringOperations
'*********************************************************************** '' @功能说明: 把字符串换为char型数组 '' @参数说明: - str [string]: 需要转换的字符串 '' @返回值: - [Array] Char型数组 '************************************************************************ public function toCharArray(byVal str) redim charArray(len(str)) for i = 1 to len(str) charArray(i-1) = Mid(str,i,1) next toCharArray = charArray end function '**************************************************************************** '' @功能说明: 把一个数组转换成一个字符串 '' @参数说明: - arr [Array]: 需要转换的数据 '' @返回值: - [string] 字符串 '**************************************************************************** public function arrayToString(byVal arr) for i = 0 to UBound(arr) strObj = strObj & arr(i) next varrayToString = strObj end function
'**************************************************************************** '' @功能说明: 检查源字符串str是否以chars开头 '' @参数说明: - str [string]: 源字符串 '' @参数说明: - chars [string]: 比较的字符/字符串 '' @返回值: - [bool] '**************************************************************************** public function startsWith(byVal str, chars) if Left(str,len(chars)) = chars then startsWith = true else startsWith = false end if end function '**************************************************************************** '' @功能说明: 检查源字符串str是否以chars结尾 '' @参数说明: - str [string]: 源字符串 '' @参数说明: - chars [string]: 比较的字符/字符串 '' @返回值: - [bool] '**************************************************************************** public function endsWith(byVal str, chars) if Right(str,len(chars)) = chars then endsWith = true else endsWith = false end if end function '**************************************************************************** '' @功能说明: 复制N个字符串str '' @参数说明: - str [string]: 源字符串 '' @参数说明: - n [int]: 复制次数 '' @返回值: - [string] 复制后的字符串 '**************************************************************************** public function clone(byVal str, n) for i = 1 to n value = value & str next clone = value end function '**************************************************************************** '' @功能说明: 删除源字符串str的前N个字符 '' @参数说明: - str [string]: 源字符串 '' @参数说明: - n [int]: 删除的字符个数 '' @返回值: - [string] 删除后的字符串 '**************************************************************************** public function trimStart(byVal str, n) value = Mid(str, n+1) trimStart = value end function '**************************************************************************** '' @功能说明: 删除源字符串str的最后N个字符串 '' @参数说明: - str [string]: 源字符串 '' @参数说明: - n [int]: 删除的字符个数 '' @返回值: - [string] 删除后的字符串 '**************************************************************************** public function trimEnd(byVal str, n) value = Left(str, len(str)-n) trimEnd = value end function '**************************************************************************** '' @功能说明: 检查字符character是否是英文字符 A-Z or a-z '' @参数说明: - character [char]: 检查的字符 '' @返回值: - [bool] 如果是英文字符,返回TRUE,反之为FALSE '**************************************************************************** public function isAlphabetic(byVal character) asciiValue = cint(asc(character)) if (65 <= asciiValue and asciiValue <= 90) or (97 <= asciiValue and asciiValue <= 122) then isAlphabetic = true else isAlphabetic = false end if end function
'**************************************************************************** '' @功能说明: 对str字符串进行大小写转换 '' @参数说明: - str [string]: 源字符串 '' @返回值: - [string] 转换后的字符串 '**************************************************************************** public function swapCase(str) for i = 1 to len(str) current = mid(str, i, 1) if isAlphabetic(current) then high = asc(ucase(current)) low = asc(lcase(current)) sum = high + low return = return & chr(sum-asc(current)) else return = return & current end if next swapCase = return end function '**************************************************************************** '' @功能说明: 将源字符串str中每个单词的第一个字母转换成大写 '' @参数说明: - str [string]: 源字符串 '' @返回值: - [string] 转换后的字符串 '**************************************************************************** public function capitalize(str) words = split(str," ") for i = 0 to ubound(words) if not i = 0 then tmp = " " end if tmp = tmp & ucase(left(words(i), 1)) & right(words(i), len(words(i))-1) words(i) = tmp next capitalize = arrayToString(words) end function
'**************************************************************************** '' @功能说明: 将源字符Str后中的'过滤为'' '' @参数说明: - str [string]: 源字符串 '' @返回值: - [string] 转换后的字符串 '**************************************************************************** public function checkstr(Str) If Trim(Str)="" Or IsNull(str) Then checkstr="" else checkstr=Replace(Trim(Str),"'","''") end if End function
'**************************************************************************** '' @功能说明: 将字符串中的str中的HTML代码进行过滤 '' @参数说明: - str [string]: 源字符串 '' @返回值: - [string] 转换后的字符串 '**************************************************************************** Public Function HtmlEncode(str) If Trim(Str)="" Or IsNull(str) then HtmlEncode="" else str=Replace(str,">",">") str=Replace(str,"<","<") str=Replace(str,Chr(32)," ") str=Replace(str,Chr(9)," ") str=Replace(str,Chr(34),""") str=Replace(str,Chr(39),"'") str=Replace(str,Chr(13),"") str=Replace(str,Chr(10) & Chr(10), "</p><p>") str=Replace(str,Chr(10),"<br> ") HtmlEncode=str end if End Function
'**************************************************************************** '' @功能说明: 计算源字符串Str的长度(一个中文字符为2个字节长) '' @参数说明: - str [string]: 源字符串 '' @返回值: - [Int] 源字符串的长度 '**************************************************************************** Public Function strLen(Str) If Trim(Str)="" Or IsNull(str) Then strlen=0 else Dim P_len,x P_len=0 StrLen=0 P_len=Len(Trim(Str)) For x=1 To P_len If Asc(Mid(Str,x,1))<0 Then StrLen=Int(StrLen) + 2 Else StrLen=Int(StrLen) + 1 End If Next end if End Function
'**************************************************************************** '' @功能说明: 截取源字符串Str的前LenNum个字符(一个中文字符为2个字节长) '' @参数说明: - str [string]: 源字符串 '' @参数说明: - LenNum [int]: 截取的长度 '' @返回值: - [string]: 转换后的字符串 '**************************************************************************** Public Function CutStr(Str,LenNum) Dim P_num Dim I,X If StrLen(Str)<=LenNum Then Cutstr=Str Else P_num=0 X=0 Do While Not P_num > LenNum-2 X=X+1 If Asc(Mid(Str,X,1))<0 Then P_num=Int(P_num) + 2 Else P_num=Int(P_num) + 1 End If Cutstr=Left(Trim(Str),X)&"..." Loop End If End Function
end class %> |
|
改进性能和样式的 24个 ASP 技巧
|
来源: 未知
作者: linfengxia
更新日期: [2005-03-12]简介
技巧 1:在 Web 服务器上缓存常用数据
技巧 2:在 Application 或 Session 对象中缓存常用数据
技巧 3:在 Web 服务器磁盘上缓存数据和 HTML
技巧 4:避免在 Application 或 Session 对象中缓存非灵活组件
技巧 5:不要在 Application 或 Session 对象中缓存数据库连接
技巧 6:妙用 Session 对象
技巧 7:在 COM 对象中封装代码
技巧 8:晚点获取资源,早点释放资源
技巧 9:进程外的执行将牺牲可靠性
技巧 10:显式使用选项
技巧 11:在子例程和函数中使用局部变量
技巧 12:将常用数据复制到脚本变量
技巧 13:避免重新定义数组
技巧 14:使用响应缓冲
技巧 15:批处理内嵌脚本和 Response.Write 语句
技巧 16:在开始长时间的任务之前先使用 Response.IsClientConnected
技巧 17:使用 <OBJECT> 标记实例化对象
技巧 18:使用 ADO 对象和其他组件的 TypeLib 绑定
技巧 19:利用浏览器的验证能力
技巧 20:在循环中避免字符串串联
技巧 21:启用浏览器和代理缓存
技巧 22:尽可能使用 Server.Transfer 替代 Response.Redirect
技巧 23:在目录 URL 尾部加斜线
技巧 24:避免使用服务器变量
--------------------------------------------------------------------------------
简介
性能是一个特性。您需要预先设计性能,或是在日后重新编写应用程序。换句话说,什么是最大限度优化 Active Server Pages (ASP) 应用程序性能的好策略?
本文为优化 ASP 应用程序和"Visual Basic(R) 脚本编辑器 (VBScript)"提供了许多技巧。对许多陷阱和缺陷进行了讨论。本文所列的建议均在 http://www.microsoft.com 及其他站点上进行了测试,而且工作正常。本文假定您对 ASP 开发有基本的理解,包括对 VBScript 和/或 JScript、ASP Application、ASP Session 和其他 ASP 内部对象(请求、响应和服务器)。
ASP 的性能,通常不止取决于 ASP 代码本身。我们并不想在一篇文章中囊括所有的至理名言,只在最后列出与性能相关的资源。这些链接包括 ASP 和非 ASP 主题,包括"ActiveX(R) 数据对象 (ADO)"、"部件对象模型 (COM)"、数据库和"Internet 信息服务器 (IIS)"配置。这些是我们喜欢的链接 - 务请关注它们。
技巧 1:在 Web 服务器上缓存常用数据
典型的 ASP 页从后端数据库检索数据,然后将结果转换为超文本标记语言 (HTML)。无论数据库的速度如何,从内存检索数据要比从后端数据库检索数据快得多。从本地硬盘读取数据通常也要比从数据库检索数据快得多。因此,通常可以通过在 Web 服务器(在内存或磁盘)上缓存数据来改善性能。
缓存是典型的空间与时间的折衷。如果恰当地缓存数据,您将看到性能会有惊人的提高。为使缓存发挥效力,它必须保持经常重用的数据,而且重新计算这些数据的代价是昂贵的或比较昂贵的。如果缓存充满了垃圾数据,则是对存储器的浪费。
不经常变化的数据也是缓存的候选数据,因为您无须担心数据与数据库的同步问题。组合框、引用表、DHTML 碎片、可扩展标记语言 (XML) 字符串、菜单项和站点配置变量(包括数据源名称 (DSN)、Internet 协议 (IP) 地址和 Web 路径)都是缓存的候选数据。注意,您可以缓存数据的表示而不是数据本身。如果 ASP 页不经常更改,而且缓存的成本也非常高(例如,整个产品目录),请考虑预先生成 HTML,而不是在每次请求时重新绘制。
数据应缓存在何处,有哪些缓存策略?数据经常缓存在 Web 服务器内存或 Web 服务器磁盘上。下面两个技巧讨论这些选项。
技巧 2:在 Application 或 Session 对象中缓存常用数据
ASP Application 和 Session 对象为在内存中缓存数据提供了方便的容器。既可以将数据赋予 Application 对象,也可将数据赋予 Session 对象,这些数据在 HTTP 调用中将保留在内存中。Session 数据按用户存储,而 Application 数据在所有用户间共享。
何时将数据载入 Application 或 Session?通常,在 Application 或 Session 启动时加载数据。要在 Application 或 Session 启动时加载数据,请在下面两函数中添加相应的代码: Application_OnStart() 或 Session_OnStart() 。这两个函数应该位于 Global.asa;如果没有,可以添加这些函数。也可以在第一次需要数据时加载数据。要进行上述操作,请在 ASP 页中添加一些代码(或编写可重用的脚本函数),这些代码检查数据是否存在,并在数据不存在时加载数据。这是称为迟缓计算的经典性能技术的例子 - 在您的确需要它之前,不进行计算。请看例子:
<% Function GetEmploymentStatusList Dim d d = Application("EmploymentStatusList") If d = "" Then ' FetchEmploymentStatusList 函数(不显示) ' 从 DB 中取出数据,返回数组 d = FetchEmploymentStatusList() Application("EmploymentStatusList") = d End If GetEmploymentStatusList = d End Function %>
可以为每一块所需的数据编写类似的函数。
数据应该以什么格式存储?任何变量类型均可存储,因为所有脚本变量是各不相同的。例如,可以存储字符串、整型或数组。通常,您将以这些变量类型之一存储 ADO 记录集的内容。若要获取 ADO 记录集衍生的数据,可以手工将数据复制到 VBScript 变量中,每次一个字段。使用一个 ADO 记录集保留函数 GetRows()、GetString() 或 Save() (ADO 2.5),会更快更简便。完整而详细的内容已超出了本文的范围。下面的演示函数使用了 GetRows() 来返回记录集数据的数组:
' 取记录集,以数组返回 Function FetchEmploymentStatusList Dim rs Set rs = createObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" FetchEmploymentStatusList = rs.GetRows() ' 以数组返回数据 rs.Close Set rs = Nothing End Function
对上面示例的进一步改进应当是缓存该列表的 HTML,而不是缓存数组。下面是一个简单的范例:
' 取记录集,以"HTML 选项"列表返回 Function FetchEmploymentStatusList Dim rs, fldName, s Set rs = createObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" s = "<select name=""EmploymentStatus">" & vbCrLf Set fldName = rs.Fields("StatusName") ' ADO 字段绑定 Do Until rs.EOF ' 下面一行违背了不要进行字符串连接, ' 但这是可以的,因为我们正在建立高速缓存 s = s & " <option>" & fldName & "</option>" & vbCrLf rs.MoveNext Loop s = s & "</select>" & vbCrLf rs.Close Set rs = Nothing ' 参见尽早释放 FetchEmploymentStatusList = s ' 以字符串返回数据 End Function
在正常的情况下,可以在 Application 或 Session 作用域中缓存 ADO 记录集本身。有两个警告:
ADO 必须为标记的自由线程 必须使用断开连接的记录集。 如果不能保证满足这两个要求,请不要缓存 ADO 记录集。在下面的非灵活组件和不要缓存连接技巧中,我们将讨论在 Application 或 Session 作用域中存储 COM 对象的危险。
如果在 Application 或 Session 作用域中存储数据,这些数据将一直保留在那儿,直到在程序中改变它、Session 过期或 Web 应用程序重新启动时为止。数据需要更新如何处理?若要用手工强制更新应用程序数据,可以调用只允许管理员访问的数据更新 ASP 页。另外,还可以通过函数,周期地自动刷新数据。下面的示例存储带缓存数据的时间戳,在指定时间间隔后刷新数据。
<% ' 未显示错误处理... Const update_INTERVAL = 300 ' 刷新时间间隔,以秒计
' 函数返回雇佣状态列表 Function GetEmploymentStatusList updateEmploymentStatus GetEmploymentStatusList = Application("EmploymentStatusList") End Function
' 定期更新缓存的数据 Sub updateEmploymentStatusList Dim d, strLastupdate strLastupdate = Application("Lastupdate") If (strLastupdate = "") Or _ (update_INTERVAL DateDiff("s", strLastupdate, Now)) Then
' 注意:此处可能有两个或多个调用。这是可以的,只不过 ' 产生几个不必要的取指令罢了(就此有一个工作区)
' FetchEmploymentStatusList 函数(不显示) ' 从 DB 中取数据,返回一个数组 d = FetchEmploymentStatusList()
' 更新 Application 对象。用 Application.Lock() ' 来确保一致的数据 Application.Lock Application("EmploymentStatusList") = d Application("Lastupdate") = CStr(Now) Application.Unlock End If End Sub
其他示例,请参阅具有 Application 数据的最快列表框(英文)。
请注意,在 Session 或 Application 对象中缓存大型数组并非上策。在访问数组元素之前,脚本语言的语法要求建立整个数组的临时副本。例如,如果在 Application 对象中缓存了将美国邮政编码映射到本地气象站的字符串数组,该字符串数组有 100,000 个元素,ASP 在找出一个字符串之前,必须将所有 100,000 个气象站复制到临时数组中。在这种情况下,建立带自定义方法的自定义组件,来存储气象站 - 或使用一个字典组件,也许更好。
请不要在倒洗澡水时把孩子一同倒掉,对这种观点的一个新的注解是:数组提供了对内存中相邻关键-数据对的快速查找和存储。索引字典比索引数组要慢。您应该根据具体情况选择能够提供最佳性能的数据结构。
技巧 3:在 Web 服务器磁盘上缓存数据和 HTML
有时,数据过多不能在内存中进行缓存。"过多"是一种定性的判断;它取决于打算消耗的内存量,还有缓存项的数量和这些项的检索频率。总之,如果有过多的数据要在内存中缓存,请考虑以文本或 XML 文件的形式,在 Web 服务器的硬盘上缓存数据。可以将在磁盘上缓存数据和在内存中缓存数据组合起来,为站点建立最优的缓存策略。
注意,在度量单个 ASP 页的性能时,在磁盘上检索数据不一定比从数据库中检索数据快。但是,缓存减轻了数据库和网络的负荷。在高负荷情况下,这将明显提高总体通信量。在查询成本很高时缓存查询的结果,缓存便非常有效,例如多表联合或复杂的存储过程,或缓存大型的结果集。按照惯例,测试竞争方案。
ASP 和 COM 提供了几种构建磁盘缓存方案的工具。ADO 记录集的 Save() 和 Open() 函数,保存和加载磁盘上的记录集。您可以使用这些方法重写上面 Application 数据缓存技巧中的范例代码,用 Save() 文件替换向 Application 对象写入数据的代码。
还有其他一些处理文件的组件:
Scripting.FileSystemObject 使您能够创建、读取和写入文件。 MSXML 是随 Internet Explorer 提供的 Microsoft(R) XML 解析器,它支持保存和加载 XML 文档。 LookupTable 对象(在 MSN 上使用的范例)是从磁盘加载简单列表的良好选择。 最后,请考虑在磁盘上缓存数据的表示,而不是数据本身。预制的 HTML 可以作为 .htm 或 .asp 文件存储在磁盘上;超级链接可以直接指向这些文件。可以使用商业工具,如 XBuilder 或 Microsoft(R) SQL Server 的 Internet 发行功能来自动化 HTML 生成过程。另外,可以将 HTML 片段 #include 到 .asp 文件。还可以使用 FileSystemObject 从磁盘读取 HTML 文件或使用 XML 进行早期调整(英文)。
技巧 4:避免在 Application 或 Session 对象中缓存非灵活组件
虽然在 Application 或 Session 对象中缓存数据是个好主意,但是缓存 COM 对象可能有严重缺陷。将常用 COM 对象嵌入 Application 或 Session 对象通常具有吸引力。遗憾的是,很多 COM 对象,包括用 Visual Basic 6.0 或更早版本编写的 COM 对象,在 Application 或 Session 对象中存储时将导致严重的瓶颈。
特别是任何非灵活组件,在 Session 或 Application 对象中缓存时将导致性能瓶颈。灵活组件是标记为 ThreadingModel=Both 的组件(它聚集了自由线程汇集器 (FTM))或标记为 ThreadingModel=Neutral 的组件(Windows(R) 2000 和 COM+ 中新增的"中性"模型。)下列组件是非灵活的:
自由线程组件(除非它们聚集了 FTM)。 单元线程组件。 单线程组件。 已配置组件(Microsoft Transaction Server (MTS)/COM+ 库和服务器包/应用程序)为非灵活组件,除非它们是"中性"线程的。单元线程组件和其他非灵活组件最适于在页作用域工作(也就是说,它们在单个 ASP 页上创建和销毁)。
在 IIS 4.0 中,标记为 ThreadingModel=Both 的组件被视为灵活的。在 IIS 5.0 中,这已经不够了。组件不仅必须标记为 Both,而且还必须聚集 FTM。灵活性文章说明了如何使得用"活动模板库"编写的 C++ 组件聚集 FTM。请注意,如果组件缓存接口指针,这些指针本身必须为灵活的、或者必须存储在"COM 全局接口表 (GIT)"中。如果不能重新编译 Both 线程组件,使它聚集 FTM,则可以将该组件标记为 ThreadingModel=Neutral 。另外,如果不希望 IIS 进行灵活性检查(这样,希望非灵活组件能够存储在 Application 或 Session 作用域中),可以在 metabase 中设置 AspTrackThreadingModel 为 True 。不主张更改 AspTrackThreadingModel 。
如果试图在 Application 对象中存储用 Server.createObject 创建的非灵活组件,IIS 5.0 将产生错误。可以通过在 Global.asa 中使用 <object runat=server scope=application ...> 解决该问题,但是不主张这样做,因为这将导致汇集和串行化,说明如下。
如果缓存非灵活组件,会发生什么错误呢?缓存在 Session 对象中的非灵活组件,将把会话"锁定"到某个 ASP 工作器线程。ASP 维护着一个工作器线程池,它向请求提供服务。通常,新的请求由第一个可用的工作器线程来处理。如果 Session 被锁定到某个线程,则该请求将不得不等待它所关联的线程变为可用。打个比方:您进入一个超市,挑选了一些食品,然后在第 3 号收款台交款。从这以后,每当您在这个超市购买食品,都不得不始终在第 3 号收款台交款,即使是在其他收款台人少或没人时。
将非灵活组件存储在 Applicaton 作用域甚至会对性能产生更严重的影响。ASP 将不得不创建专用的线程来运行非灵活的、Applicaton 作用域内的组件。这将导致两种后果:所有调用不得不被汇集到该线程,而且所有调用被串行化。汇集意味着:参数不得不存储在内存的共享区;对该专用线程执行昂贵的上下文切换;组件的方法被执行;结果汇集到共享区域;以及经过另一个昂贵的上下文切换,使控制权返回原来的线程。串行化意味着所有方法必须一个挨一个地运行(同一时刻只能运行一个方法)。两个不同的 ASP 工作器线程不可能同时执行共享组件上的方法。这将扼杀并行机制,尤其是在多处理器计算机上。更坏的是,所有非灵活的、Application 作用域内的组件都将共享一个线程("Host STA"),所以串行化的影响更加严重。
是否感到困惑?下面我们提出几个通用规则。如果您正在用 Visual Basic (6.0) 或更早版本编写对象,请不要将它们缓存在 Application 或 Session 对象中。如果您不知道对象的线程模型,就不要缓存它。不要缓存非灵活对象,而应当在每页上创建并释放它们。对象将直接运行在 ASP 工作器线程上,这样,将不会发生汇集或串行化。如果 COM 对象正运行在 IIS 框中,而且如果它们没有花很长时间来初始化和取消,性能将是足够的。注意,不要用该方法使用单线程对象。小心:VB 可以创建单线程的对象!如果您必须以该方式使用单线程的对象(如 Microsoft Excel 电子表格),则不要期望有很高的吞吐量。
当 ADO 被标记为自由线程时,则缓存 ADO 记录集是安全的。要将 ADO 标记为自由线程,请使用 Makfre15.bat 文件,该文件通常位于如下目录中:\\Program Files\Common\System\ADO。
警告: 如果您正在用 Microsoft Access 作为数据库,则不应当将 ADO 标记为自由线程。通常,ADO 记录集还必须是断开连接的,如果您不能控制站点的 ADO 配置(例如,您是独立的软件厂商 [ISV],将 Web 应用程序卖给客户,然后由他们来管理他们自己的配置),那么不缓存记录集可能会更好。
词典组件也是灵活对象。LookupTable 从数据文件加载它的数据,并且它对组合框数据和配置信息是有用的。来自 Duwamish Books 的 PageCache 对象提供了目录语义,和 Caprock Dictionary 的表现一样。这些对象或它们的派生对象可以构成有效缓存策略的基础。注意,Scripting.Dictionary 对象不是灵活的,所以不应当存储在 Application 或 Session 作用域。
技巧 5:不要在 Application 或 Session 对象中缓存数据库连接
缓存 ADO 连接通常是不好的策略。如果一个 Connection 对象存储在 Application 中,并在所有页上使用,那么所有页将竞争使用该连接。如果 Connection 对象存储在 ASP Session 对象中,那么将为每个用户创建数据库连接。这将连接池的好处毁于一旦,并对 Web 服务器和数据库产生不必要的压力。
取代缓存数据库连接的方法是,在每个使用 ADO 的 ASP 页上创建并取消 ADO 对象。这是个有效的方法,因为 IIS 具有内置的数据库连接池。更准确的说,IIS 自动启用 OLEDB 和 ODBC 连接池。这确保了创建并取消每个页上的连接将是有效的。
由于被连接的记录集中存储有对数据库连接的引用,所以,不应当在 Application 或 Session 对象中缓存被连接的记录集。但是,可以安全地缓存断开连接的记录集,因为它不包含对其数据连接的引用。要断开记录集的连接,请执行如下两个步骤:
Set rs = Server.createObject("ADODB.RecordSet") rs.CursorLocation = adUseClient ' 第 1 步
' 植入带数据的记录集 rs.Open strQuery, strProv
' 现在断开记录集同数据提供者和数据源的连接 rs.ActiveConnection = Nothing ' 第 2 步
有关连接池的详细信息,请参阅 ADO 和 SQL Server(英文)引用。
技巧 6:妙用 Session 对象
在肯定了在 Applications 和 Sessions 中缓存的优点之后,我们建议您避免使用 Session 对象。下面将会谈到,当用于忙碌站点时,Sessions 有几个缺点。所谓忙碌,通常是指站点每秒请求数百页或同时有数千个用户。该技巧对于必须进行水平扩展的站点,即那些利用多个服务器来适应负载或执行容错功能的站点来说,更加重要。对于较小的站点,如 intranet 站点,Sessions 的便利,与开销相比也是值得的。
为了翻新,ASP 自动为每个访问 Web 服务器的用户创建一个 Session。每个 Session 有大约 10 KB 内存开销(在存储在 Session 中的任何数据中是最高的),并使所有的请求都慢了一点。Session 一直保持活动状态,直到达到可配置的超时(通常 20 分钟)为止。
Session 最大的问题不是性能而是可伸缩性。Session 不能跨越 Web 服务器;一旦在一个服务器上创建了 Session,它的数据就保持在那里。这意味着,如果您在 Web 领域中使用 Sessions,您将不得不为每个用户的请求设计一种策略,以便始终将这些请求引向用户的 Session 所在的服务器。这被称为将用户"粘"到 Web 服务器上。术语"粘性会话"即来源于此。由于 Session 没有保持到磁盘上,所以,当 Web 服务器崩溃时,被"粘住"的用户将丢失他们的 Sessions 状态。
用于实施粘性会话的策略包括硬件和软件解决方案。如 Windows 2000 Advanced Server 中的网络负载平衡解决方案和 Cisco 公司的"本地指向器"解决方案可以实施粘性会话,但以牺牲一些可伸缩性为代价。这些解决方案并不完美。我们不主张您现在全盘推翻您的软件解决方案(我们过去常用 ISAPI 筛选器和 URL 矫直对方案进行检查)。
Application 对象也不能跨越服务器;如果您需要在 Web 领域内共享并更新 Application 数据,则需要使用后端数据库。但只读的 Application 数据在 Web 领域中仍然有用。
如果只是为了增加正常运行时间(用于处理故障转移和服务器维护),大多数执行重要任务的站点将需要部署至少两台 Web 服务器。所以,在设计执行重要任务的应用程序时,您将需要实施"粘性会话",或者简单地避开 Sessions 以及其他任何在单个 Web 服务器上存储用户状态的状态管理技术。
如果当前没有使用 Sessions,请确保将它们关闭。可以通过"Internet 服务管理器"(请参阅 ISM 文档)来为应用程序执行该操作。如果决定使用 Sessions,可以采取几个方法来将对性能的影响降低到最小。
可以将不需要 Sessions 的内容(如"帮助"屏幕、访问者区域等)移动到关闭了 Sessions 的、单独的 ASP 应用程序中。可以逐页提示 ASP:在给定的页中您不需要 Session 对象;使用位于 ASP 页顶端的如下指令:
<% @EnableSessionState=False %>
使用该指令的一个很好的原因是,Session 给框架集带来了有趣的问题。ASP 保证任何时候只执行一个来自 Session 的请求。这样可以确保如果浏览器为一个用户请求了多个页时,在每一时刻只有一个 ASP 请求将进入 Session;这就避免了在访问 Session 对象时出现多线程问题。遗憾的是,结果,框架集中的所有页均被以串行化方式绘制,一个接一个地,而不是同时地。这样,用户可能不得不等待很长时间才能得到所有框架内容。这意味着:如果某些框架页不信任 Session,一定要使用 @EnableSessionState=False 指令告诉 ASP。
作为使用 Session 对象的替代方式,有很多方法可以用来管理 Session 状态。对于状态数量较小的情况(不到 4 KB),通常建议使用 Cookies、QueryString 变量和隐藏形式的变量。对于较大数量的数据,如购物推车,则使用后端数据库是最合适的选择。关于在 Web 服务器领域中的状态管理技术已经有很多资料。详细信息,请参阅 会话状态(英文)。
技巧 7:在 COM 对象中封装代码
如果您有很多 VBScript 或 JScript,那么您可以通过把代码移动到已编译的 COM 对象来经常改进它们的性能。已编译的代码通常比被解释代码运行得更快。已编译的 COM 对象可以通过"早期绑定"访问其他 COM 对象,这种调用 COM 对象方法的手段,比脚本所使用的"后期绑定"更有效。
将代码封装在 COM 对象种有如下好处(超越性能):
COM 对象是将表达逻辑与业务逻辑分隔开来的好办法。 COM 对象启用了代码重用。 很多开发商发现,用 VB、C++ 或 Visual J++ 书写的代码,比 ASP 更容易调试。 COM 对象有一些缺点,包括初始开发时间以及需要不同的编程技巧。需要警告您的是,封装"少"量的 ASP 可能会导致性能降低,而不是提高。通常,在少量 ASP 代码封装到 COM 对象时出现这样的情况。这时候,创建和调用 COM 对象的开销,超过了已编译代码的好处。至于 ASP 脚本和 COM 对象代码怎样合并才能产生最佳性能还有待测试。注意,与 Windows NT(R) 4.0/IIS 4.0 相比,Microsoft 已经在 Windows 2000/IIS 5.0 中极大地提高了脚本和 ADO 性能。这样,已编译代码对 ASP 代码的性能优势已经随着 IIS 5.0 的引入而降低。
有关在 ASP 中使用 COM 对象的优缺点的更多讨论,请参阅 ASP 组件准则和用 COM 和 Microsoft Visual Basic 6.0 对分布式应用程序进行编程(英文)。如果您的确部署了 COM 组件,要对它们进行强度测试是非常重要的。实际上,所有 ASP 应用程序都应当作为正式过程进行强度测试。
技巧 8:晚点获取资源,早点释放资源
这是个小技巧。通常,最好晚点获取资源而要早点释放资源。这些资源包括 COM 对象、文件句柄和其他资源。
ADO 连接和记录集是这种优化的首要目标。当您使用完记录集,就是说用它的数据打印完一个表格后,请立即将它释放,而不是等到页的末尾。将您的 VBScript 变量设置为 Nothing 是最好的做法。不要让记录集简单地脱离作用域。同时,应当释放任何有关的 Command 或 Connection 对象。(不要忘了对记录集或"连接"调用 Close() ,在将它们设置为 = Nothing 之前。)这将缩短数据库必须为您调整资源的时间跨度,并将数据库连接尽可能快地释放给连接池。
技巧 9:进程外的执行将牺牲可靠性
ASP 和 MTS/COM+ 都有允许您以可靠性换取性能的配置选项。当建立和部署应用程序时,应当理解这种交换。
ASP 选项
ASP 应用程序可以配置为以三种方式之一运行。在 IIS 5.0 中引入了术语"隔离级"来描述这些选项。三个隔离级值分别是低、中和高:
低级隔离。该隔离级在所有版本的 IIS 中受到支持,并且是最快的。它在主 IIS 进程 Inetinfo.exe 中执行 ASP。如果 ASP 应用程序崩溃,则 IIS 也将崩溃。(要在 IIS 4.0 下重新启动 IIS,Web 站点管理员需要使用工具,如 InetMon,来监视站点,如果服务器失败,将运行批处理文件来重新启动服务器。而 IIS 5.0 则引入了可靠的重新启动,它将自动重新启动失败的服务器。) 中级隔离。IIS 5.0 引入了这个新隔离级,它称为进程外的,这是因为 ASP 运行在 IIS 进程之外。在中级隔离中,所有被配置按"中级"运行的 ASP 应用程序,将共享单个进程空间。这将减少在一个服务器上运行多个进程外的 ASP 应用程序所需的进程数。中级是 IIS 5.0 中默认的隔离级。 高级隔离。在 IIS 4.0 和 IIS 5.0 中受到支持,高级隔离也是进程外的。如果 ASP 崩溃,则 Web 服务器并不崩溃。ASP 应用程序将在下一个 ASP 请求时自动重新启动。使用高级隔离,每个被配置为按高级运行的 ASP 应用程序,将在其自己的进程空间中运行。这样可以保护 ASP 应用程序彼此不受干扰。它的缺点是它需要为每个 ASP 应用程序建立独立的进程。当需要在一个服务器上主持十多个应用程序时,会增加很多开销。 那么,哪个选项是最好的呢?在 IIS 4.0 中,运行进程外的应用程序会极大地影响性能。在 IIS 5.0 中,做了许多工作,使得进程外运行 ASP 应用程序对性能产生的影响降到了最低。实际上,在大多数测试中,在 IIS 5.0 中的 ASP 进程外应用程序,要比 IIS 4.0 中的进程内应用程序运行得更快。无论如何,进程内(低隔离级)在两种平台上仍然产生了最好的性能。但是,如果您的命中率相对较低或最大吞吐量较低,选择低隔离级不会有太大的好处。所以,除非您需要每个 Web 服务器每秒处理数百或数千个页面,否则没有必要选择低隔离级。同样,应当测试多种配置并判断哪种情形最适合您。
注意: 当您进程外运行 ASP 应用程序(中级或高级隔离)时,则在 NT4 上它们将运行在 MTS 中,而在 Windows 2000 上它们将运行在 COM+ 中。即,在 NT4 上它们运行在 Mtx.exe 中,而在 Windows 2000 上它们运行在 DllHost.exe 中。在"任务管理器"中,您可以看见这些正在运行的进程。还可以看见 IIS 如何为进程外的 ASP 应用程序配置 MTS 程序包或 COM+ 应用程序。
COM 选项
COM 组件也有三个配置选项,虽然与 ASP 选项不完全相似。COM 组件可以被:"不配置"、配置为"库应用程序"或配置为"服务器应用程序"。"不配置"是指不向 COM+ 注册组件。组件将运行在调用者的进程空间,就是说,它们是"进程中"的。"库应用程序"也是进程中的,但受惠于 COM+ 的服务,包括安全性、事务和环境支持。"服务器应用程序"被配置为在其自己的进程空间中运行。
您可能看到,不配置的组件比库应用程序优点稍微多些。您还可能看到"库应用程序"比"服务器应用程序"有很大的性能优点。这是因为"库应用程序"与 ASP 运行在同一个进程中,而"服务器应用程序"则运行在自己的进程中。内部进程调用的开销要比进程内调用的开销大得多。而且,当在进程之间传递数据(如记录集)时,必须在两个进程之间复制所有的数据。
缺点!当使用"COM 服务器应用程序"时,如果要在 ASP 和 COM 之间传递对象,请确保对象实现"按值汇集",即 MBV。实现 MBV 的对象将其自身从一个进程复制到另一个进程。这比另一种方式好,在另一种方式中,对象留在创建它的进程中,而其他进程则重复调用创建使用该对象的进程。被断开连接的 ADO 记录集将是按值汇集的,已连接的记录集则不是。Scripting.Dictionary 并不实现 MBV,不会在进程之间传递。最后,要另外告诉 VB 程序员的是:MBV 不是通过传递参数 ByVal 获得的。MBV 是由原始组件创作者实现的。
怎么办?
如果您想要以性能与可靠性的合理交换来完成您的配置,我们的推荐如下:
在 IIS 4.0 上,使用 ASP 的低隔离级别,并使用"MTS 服务器包"。 在 IIS 5.0 上,使用 ASP 的中隔离级别,并使用"COM+ 库应用程序"。 这些是很一般的准则;通常让公司以中或高隔离级别运行 ASP,而单一目的的 Web 服务器可运行于低隔离级别。请权衡折中并自行决定满足需求的配置。
技巧 10:显式使用选项
在 .asp 文件中显式使用 选项 Explicit 。置于 .asp 文件开头的这一指令,强制开发人员声明所有要使用的变量。许多开发人员认为这有助于调试应用程序,因为它避免了错误键入变量名称而不经意地新建变量(例如, MyXLMString=... 而非 MyXMLString=) 。
也许更重要的是,声明的变量比未声明的变量快。实际上,脚本运行时,在每次使用未声明变量时按照名称引用。而声明的变量,在编译或运行时分配了序号。这样,声明的变量按照该序号引用。由于 选项 Explicit 强制变量声明,因此保证声明了所有变量而实现快速访问。
技巧 11:在子例程和函数中使用局部变量
局部变量是在子例程和函数中声明的变量。在子例程和函数中,局部变量访问要快于全局变量访问。使用局部变量还可以使代码更加清晰,因此尽可能使用局部变量。
技巧 12:将常用数据复制到脚本变量
在 ASP 中访问 COM 时,应该将常用的对象数据复制到脚本变量中。这将削减 COM 方法的调用,COM 方法的调用与访问脚本变量相比,要相对昂贵些。在访问 Collection 和 Dictionary 对象时,这一技术也可以削减了昂贵的查找。
通常,如果打算多次访问对象数据,请将数据放入脚本变量。该优化的主要目标是 Request 变量(Form 和 QueryString 变量)。例如,您的站点可能传递一个名为 UserID 的 QueryString。假定该 UserID 变量要在特定页中引用 12 次。请不要调用 Request("UserID") 12 次,而在 ASP 页的开头将 UserID 赋予某个变量。然后就在页中使用该变量。这将节省 11 次 COM 方法调用。
在实际中,访问 COM 属性或方法暗藏着繁复的过程和大量的开销。下面是一个示例,它只是些相当普通的代码(从语法上讲):
Foo.bar.blah.baz = Foo.bar.blah.qaz(1) If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ' ...
在运行这段代码时,将发生下列事件:
变量 Foo 被解析为全局变量。 变量 bar 被解析为 Foo. 的成员。这将产生 COM 方法调用。 变量 blah 被解析为 Foo.bar 的成员。这也将产生 COM 方法调用。 变量 qaz 被解析为 foo.bar.blah 的成员。是的,这也将产生 COM 方法调用。 调用 Foo.bar.blah.quaz(1) 。又一次产生 COM 方法调用。理解这幅图了吗? 执行步骤 1 到 3 将再次解析 baz 。系统不知道调用 qaz 是否更改对象模型,因此步骤 1 到 3 必须再次执行解析 baz 。 将 baz 解析为 Foo.bar.blah 的成员。进行属性置入。 再次执行步骤 1 到 3 并解析 zaq 。 再次执行步骤 1 到 3 并解析 abc 。 正如所见,这是非常可怕的低效率(而且非常慢)。用 VBScript 编写该代码实现的快速方法为:
Set myobj = Foo.bar.blah ' 对 blah 做一次解析 Myobj.baz = myobj.qaz(1) If Myobj.zaq = Myobj.abc Then '...
如果您使用的是 VBScript 5.0 或更高版本,则可用 With 语句来写这段代码:
With Foo.bar.blah .baz = .qaz(1) If .zaq = .abc Then '... ... End With
请注意该技巧对 VB 编程同样有效。
技巧 13:避免重新定义数组
尽量避免 Redim 数组。从关心性能的角度来说,如果计算机受物理内存的限制,最好一开始将数组的维数设置为最差方案 - 而不要将维数设置为最佳方案,再根据需要重新定义维数。这并不意味着明知道不需要那么多而就是应该分配太多的内存。
下面代码展示了您没有必要地使用了 Dim 和 Redim 来解决。
<% Dim MyArray() Redim MyArray(2) MyArray(0) = "hello" MyArray(1) = "good-bye" MyArray(2) = "farewell" ... ' 一些别的代码中,这里您不需要更多的空间,然后 ... Redim Preserve MyArray(5) MyArray(3) = "more stuff" MyArray(4) = "even more stuff" MyArray(5) = "yet more stuff" %>
更好的办法是只须一开始 Dim 数组为正确的大小(本例中为 5),而不是 Redim 数组,再加大数组。这可能会浪费一点儿内存(如果没有用尽所有元素),但是获得的是速度。
技巧 14:使用响应缓冲
您可以通过打开"响应缓冲区"来缓冲值得输出的整个页。这将写入浏览器的数据量降为最小,从而提高总体性能。每次写入都会有大量开销(包括 IIS 和通过电缆发送的数据量),因此写入的越少越好。TCP/IP 的工作效率,在发送少量大的数据块时明显高于发送大量小的数据块时,原因在于它的低速启动和 Nagling 算法(用于最小化网络阻塞)。
打开响应缓冲有两种方法。第一种,可以使用"Internet 服务管理器"为整个应用程序打开响应缓冲。这是推荐的方法,在 IIS 4.0 和 IIS 5.0 中,在默认情况下,为新的 ASP 应用程序打开响应缓冲。第二种,逐页将下列代码行放在 ASP 页的开头,从而启用响应缓冲:
<% Response.Buffer = True %>
该行代码必须在任何响应数据写入浏览器之前执行(也就是说,在任何 HTML 出现在 ASP 脚本中之前和任何 Cookies 被使用 Response.Cookies 集合设置之前)。通常,最好是为整个应用程序打开响应缓冲。这允许省略上面每页中的代码行。
Response.Flush
响应缓冲的通病是用户感觉 ASP 页响应迟钝(尽管总体响应时间改善了),因为他们需要等到整个页生成后才能看见该页。对于长时间运行的页面,可以通过设置 Response.Buffer = False 关闭响应缓冲。但是,更好的策略是使用 Response.Flush 方法。该方法刷新由 ASP 绘入浏览器的所有 HTML。例如,绘制了具有 1,000 行的表的 100 行后,ASP 可以调用 Response.Flush 强制将结果绘制到浏览器;这允许用户在其余的行准备好之前先看到头 100 行。该技术给了您两个举世无双的好东西 - 响应缓冲与浏览器中数据的逐步显示的组合。
(注意,在上面 1,000 行表的示例中,许多浏览器,在看到 </table> 结束标记之前不会开始绘制表。请检查目标浏览器的支持性。要解决该问题,请将表分割为具有较少行的多个表,然后在每个表后面调用 Response.Flush 。新版本的 Internet Explorer 将在表完全下载之前绘制表,特别是如果指定表的列宽则绘制速度更快;这避免强制 Internet Explorer 通过度量每个单元格的内容来计算列宽。)
响应缓冲的另一个通病是在生成大型页时将使用服务器的大量内存。对于该问题,除了要求生成大型页的技巧外,还可以通过巧妙地使用 Response.Flush 来解决。
技巧 15:批处理内嵌脚本和 Response.Write 语句
VBScript 语法 <% = expression %> 将" 表达式 "的值写入 ASP 输出流。如果响应缓冲没有打开,则这些语句的每一句都会导致通过网络,以许多小型包的形式,向浏览器写入数据。这是非常慢的。另外,解释少量脚本和 HTML,将导致在脚本引擎和 HTML 之间切换,也降低了性能。因此,请使用下面技巧:用对 Response.Write 的一个调用,替换内嵌的密集组合表达式。例如,在下面范例中,每行每字段有一个对响应流的写入,每行都有许多 VBScript 和 HTML 之间的切换:
<table> <% For Each fld in rs.Fields %> <th><% = fld.Name %></th> <% Next While Not rs.EOF %> <tr> <% For Each fld in rs.Fields %> <td><% = fld.Value %></td> <% Next </tr> <% rs.MoveNext Wend %> </table>
下面是更有效的代码,每行中有一个对响应流的写入。所有代码均包含在一个 VBScript 块内:
<table> <% For each fld in rs.Fields Response.Write ("<th>" & fld.Name & "</th>" & vbCrLf) Next While Not rs.EOF Response.Write ("<tr>") For Each fld in rs.Fields %> Response.Write("<td>" & fld.Value & "</td>" & vbCrLf) Next Response.Write "</tr>" Wend %> </table>
当响应缓冲被禁用时,本技巧的作用更大。最好启用响应缓冲,然后观察批处理 Response.Write 是否对性能有帮助。
(在这一特例中,构建表的主体的嵌套循环 ( While Not rs.EOF... ) 可以被精心构造的、对 GetString 的调用所替代。)
技巧 16:在开始长时间的任务之前先使用 Response.IsClientConnected
如果用户失去耐心,他们可以在开始执行他们的请求之前放弃 ASP 页。如果他们单击了 Refresh 或跳转到服务器的其他页上,在 ASP 请求队列的末尾将有一个新的请求,而在队列的中间有一个断开连接的请求。这通常发生在服务器处于高负荷的情况下(它有一个很长的请求队列,相应的响应时间也很长),这只能使情况更糟。如果用户不再连接,将没有执行 ASP 页的点(特别是低速、重量级的 ASP 页)。可以使用 Response.IsClientConnected 属性检查这种情况。如果它返回 False ,则应调用 Response.End 并放弃该页的剩余内容。实际上,每当 ASP 要执行新的请求时,IIS 5.0 便将该方法编码,来检查队列中的请求有多长。如果在那里超过了 3 秒钟,ASP 会检查客户是否仍然连接着,如果客户已断开连接,就立即结束该请求。您可以使用 metabase 中的 AspQueueConnectionTestTime 设置,调整这 3 秒的超时时间。
如果有某页执行了很长时间,您可能还想按一定的时间间隔检查 Response.IsClientConnected 。在启用响应缓冲之后,按一定的时间间隔执行 Response.Flush ,告诉用户正在进行的是哪些事情,是个好办法。
注意 在 IIS 4.0 中, Response.IsClientConnected 将不能正常工作,除非首先执行 Response.Write 。如果启用了缓冲,也需要执行 Response.Flush 。在 IIS 5.0 中则不必如此 - Response.IsClientConnected 工作得很好。在任何情况下, Response.IsClientConnected 都要有些开销,所以,只有在执行至少要用 500 毫秒(如果想维持每秒几十页的吞吐量,这是一个很长的时间了)的操作前才使用它。作为通常的规则,不要在紧密循环的每次迭代中调用它,例如当绘制表中的行,可能每 20 行或每 50 行调用一次。
技巧 17:使用 <OBJECT> 标记实例化对象
如果需要引用不能在所有代码路径中使用的对象(尤其是服务器 - 或应用程序 - 作用域的对象),则使用 Global.asa 中的 <object runat=server id=objname> 标记来声明它们,而不是使用 Server.createObject 方法。 Server.createObject 立刻创建对象。如果以后不使用那个对象,就不要浪费资源。 <object id=objname> 标记声明了 objname,但实际上 objname 此时并没有创建,直到它的方法或属性第一次被使用时才创建。
这是迟缓计算的另一个例子。
技巧 18:使用 ADO 对象和其他组件的 TypeLib 声明
当使用 ADO 时,开发人员经常包含 adovbs.txt 来获得对 ADO 不同常量的访问权。该文件必须包含在要使用这些常量的每一页中。该常量文件非常大,给每个 ASP 页增加了很多编译时间和脚本大小方面的开销。
IIS 5.0 提供了绑定到组件类型库的能力。允许您在每个 ASP 页上引用一次类型库并使用它。每页不需要为编译常量文件付出代价,并且组件开发人员不必为在 ASP 中的使用而生成 VBScript #include 文件。
要访问 ADO 类型库,请将下列语句之一放入 Global.asa 中。
<!-- METADATA NAME="Microsoft ActiveX Data Objects 2.5 Library" TYPE="TypeLib" UUID="{00000205-0000-0010-8000-00AA006D2EA4}" -->
或者
<!-- METADATA TYPE="TypeLib" FILE="C:\Program Files\Common Files\system\ado\msado15.dll" -->
技巧 19:利用浏览器的验证能力
流行的浏览器具有对以下功能的高级支持,例如 XML、DHTML、Java 小程序以及远程数据服务。请尽量利用这些功能。所有这些技术,都可以通过执行客户端的验证和数据缓存,减少了与 Web 服务器之间的往返。如果您正在运行智能浏览器,该浏览器可以为您进行一些验证(例如,在运行 POST 之前检查信用卡的校验和否有效)。重申一次,请尽量使用这些功能。由于削减了客户端到服务器的往返路程,将减少对 Web 服务器的压力,并且削减了网络通信量(虽然发送给浏览器的初始页面可能更大),服务器访问的所有后端资源也削减了。而且用户不必经常提取新页,使用户的感受好一些。这并不减轻对服务器端验证的需要。还是应该经常进行服务器端的验证。这样能够防止由于某些原因从客户端来的坏数据,例如黑客,或者不运行客户端验证程序的浏览器。
许多站点由独立于浏览器创建的 HTML 组成。这一点经常阻碍开发人员利用可以提高性能的流行浏览器功能。对于真正高性能的、必须关心浏览器的站点,良好的策略是针对流行的浏览器优化您的页面。在 ASP 中使用"浏览器性能组件",很容易检测到浏览器的功能。诸如 Microsoft FrontPage 等工具,能帮助您设计使用所希望的目标浏览器和 HTML 版本的代码。更详细的讨论,请查看 When is Better Worse? Weighing the Technology Trade-Offs(英文)。
技巧 20:在循环中避免字符串串联
许多人在循环中创建类似这样的字符串:
s = "<table>" & vbCrLf For Each fld in rs.Fields s = s & " <th>" & fld.Name & "</th> " Next
While Not rs.EOF s = s & vbCrLf & " <tr>" For Each fld in rs.Fields s = s & " <td>" & fld.Value & "</td> " Next s = s & " </tr>" rs.MoveNext Wend
s = s & vbCrLf & "</table>" & vbCrLf Response.Write s
这种方法有几个问题。首先,重复连接字符串所花费的时间,以二次方曲线的速率增长;粗略地计算,运行循环所花费的时间,与记录数乘以字段数的平方成正比。举一个简单的例子,便能清楚地说明这一点。
s = "" For i = Asc("A") to Asc("Z") s = s & Chr(i) Next
在第一次迭代中,得到一个字符的字符串 "A" 。在第二次迭代中,VBScript 必须重新分配字符串并复制两个字符 "AB" 到 s 。在第三次迭代中,它必须再次重新分配 s ,并复制三个字符到 s 。在第 N 次(26 次)迭代中,它必须重新分配并复制 N 个字符到 s 。就是 1+2+3+...+N 的和,为 N*(N+1)/2 次复制。
在以上记录集的例子中,如果有 100 条记录和 5个字段,则内部的循环将执行 100*5 = 500 次,并且完成所有复制和重新分配所花费时间,将与 500*500 = 250,000 成正比。对一个大小适度的记录集,将有很多次复制。
在该例子中,代码可以改进:字符串的连接将被 Response.Write() 或内嵌脚本 ( <% = fld.Value %> ) 所替代。如果打开响应缓冲,这个操作将会很快,因为 Response.Write 仅仅将数据添加到响应缓冲的末尾。不再重新分配,因而非常有效。
特别是在将 ADO 记录集转换到 HTML 表时,请考虑使用 GetRows 或 GetString。
如果用 JScript 连接字符串,强烈建议使用 += 操作符;即用 s += "某字符串", 而不是 s = s + "某字符串" 。
技巧 21:启用浏览器和代理缓存
默认情况下,ASP 禁用浏览器和代理中的缓存。这将很有意义,因为 ASP 生来就是动态的,具有潜在地对时间敏感的信息。如果有一个不需要对每次查看进行刷新的页,则应该启用浏览器和代理缓存。这使得浏览器和代理能在某一段时间内,使用某一页的缓存副本,这时间的长短可以控制。缓存能明显减轻服务器负荷,使用户的感受好一些。
哪种动态页可以缓存?举例说明:
天气页,每 5 分钟更新一次。 列出新闻的主页或新闻发布的主页,每天更新 2 次。 公共基金运营列表,基本的统计数小时更新 1 次。 请注意,使用浏览器或代理缓存,只有很少的命中被记录到 Web 服务器上。如果想精确测量所有页面查看或者张贴广告,也许不喜欢使用浏览器和代理缓存。
浏览器缓存是由 Web 服务器发往浏览器的 HTTP 截至期限标题控制的。ASP 提供了两种发送标题的机制。要将页面设置为在未来某个分钟数后过期,请设置 Response.Expires 属性。以下的例子通知浏览器:内容在 10 分钟后过期:
<% Response.Expires = 10 %>
设置 Response.Expires 为负数或 0 则禁用缓存。一定要使用较大的负数,例如 -1000 (大于一天),来克服服务器时钟和浏览器时钟之间的差异。第二个属性 Response.ExpiresAbsolute ,允许设置内容过期的指定时间:
<% Response.ExpiresAbsolute = #May 31,2001 13:30:15# %>
如果不想使用 Response 对象设置过期时间,可以将 <META> 标记写入 HTML,通常写在 HTML 文件的 <HEAD> 内部。一些浏览器会响应这条指令,但代理不会。
<META HTTP-EQUIV="Expires" VALUE="May 31,2001 13:30:15">
最后,可以标识内容对 HTTP 代理缓存是否有效,请使用 Response.CacheControl 属性。设置属性为"Public",允许代理缓存内容。
<% Response.CacheControl = "Public" %>
默认情况下,该属性设置为"Private"。注意,不应当为显示某用户专用数据的页启用代理缓存,因为代理也许为属于其他用户的用户页面服务。
技巧 22:尽可能使用 Server.Transfer 替代 Response.Redirect
Response.Redirect 通知浏览器,请求一个不同的页面。该函数经常用于重定向用户到登录或错误页面。既然重定向强制一个新页请求,浏览器就必须做两次到 Web 服务器的往返,而且 Web 服务器必须处理额外的请求。IIS 5.0 引入一个新的函数, Server.Transfer ,该函数执行传送到相同服务器上的不同 ASP 页。这样避免了额外的、从浏览器到 Web 服务器的往返,从而改善了整体系统性能,同时改善了对用户的响应时间。请查看重定向中的新方向(英文),它讨论了 Server.Transfer 和 Server.Execute 。
也可以查看Leveraging ASP in IIS 5.0中有关 IIS 5.0 和 ASP 3.0 新功能的完全列表。(英文)
技巧 23:在目录 URL 尾部加斜线
相关的技巧是,一定要定在指向目录的 URL 尾部加斜线 (/) 。如果省略了斜线,浏览器将向服务器提出请求,仅通知它正寻找一个目录。然后浏览器发出第二个请求,在 URL 末尾添加斜线,然后服务器将那个目录的默认文档作为响应,或者如果没有默认文档并且目录浏览已被启用,就以目录列表作为响应。添加了斜线便省去了第一个没用的往返。出于对用户的友好,也许想要在显示的名称的末尾省略斜线。
例如,写:
<a href="http://msdn.microsoft.com/workshop/" title="MSDN Web Workshop">" target=_blank>http://msdn.microsoft.com/workshop</a>
它还适用于指向在 Web 站点主页的 URL:请使用下面的: <a href=",不要用' target=_blank>http://msdn.microsoft.com/">,不要用 <a href="./' target=_blank>http://msdn.microsoft.com">.
技巧 24:避免使用服务器变量
访问服务器变量将引起 Web 站点向服务器提出特殊的请求,然后收集所有的服务器变量,并不止是需要的那个。这好像从发霉的阁楼中的文件夹中检索某条特殊的信息一样。当想要某条信息时,在访问该信息之前必须先上阁楼取得文件夹。这与请求服务器变量时,性能访问出现第一次请求服务器变量所发生的一样。后续的对其他服务器变量的访问不会引起性能访问。
从不访问不合格的 Request 对象(例如, Request("Data") )。对于不在 Request.Cookies 、 Request.Form 、 Request.QueryString 或 Request.ClientCertificate 中的项,有对 Request.ServerVariables 的隐含调用。 Request.ServerVariables 集合比其他集合慢很多。
|
|
動手寫個小元件(元件入門)
|
動手寫個小元件(元件入門)
主題
這篇文章主要是為想將自己的ASP水平提高的人寫的! 把ASP代碼變成元件,開發者不僅是加快了ASP的速度,而且也能保護自己的代碼.這篇文章寫出來,也是為了給想開發元件網友上一堂入門課! 下面,我們會來編寫一個非常簡單的元件,重點是知道怎樣開發DLL元件,而不是其複雜的代碼!這些都要靠你們自己以後的努力了.
服務器端元件
首先,服務器端的元件要有別於客戶端的元件.客戶端的元件是通過網絡傳輸,依靠HTML來起作用.而且只能在IE上有用.但是服務器端的元件是運行在服務器端,它在服務器上執行各種操作.因此,所有的瀏覽器都能享用,它依靠的是服務器而不是瀏覽器.
當IIS被請求執行一個ASP程序,它首先會在ASP文件中找到 〈% %>標籤之間的代碼,並且執行它(也可以是〈script runat=server>〈/script>之間的代碼).如果這個ASP程序在先前被調用過,那麼它就會用記憶體中的編譯過的程序來嚮用戶返回HTML代碼,如果沒有,那麼它就重新編譯.這裡ASP就比CGI多一點速度優勢,因為CGI是每一個請求都使用一個執行緒.這樣就大大消耗了服務器的資源.
想不想你寫的程序自己就能在IIS運行!?!現在你就行了!使用VB5(當然現在是VB6了),你就能建立Dynamic Linked Libraries (DLL 文件),它能在IIS上直接運行(如果有asp文件來請求的話).
系統和軟件的要求
你需要一個32位的操作系統來運行ASP.當然你也得安裝IIS或PWS.我們下面的程序是在windows95+PWS+VB5的環境下開發的.
我們開始吧
啟動你的VB,選擇ActiveX圖標.這個圖標可以在新建工程找到!VB會提供一個內定的工程名(project1)和類名(class1).我們會將這兩個名字都改掉.在改名之前,請首先確認我們擁有Microsoft Active Server Pages Object Library,它在我們的程序非常有用.從菜單中選擇"工程",然後在其中選擇"引用",就會出現"引用"窗口 從中選擇Microsoft Active Server Pages Object Library.
給工程和類命名
現在我們來根據自己的愛好來為project1和class1來命名吧!給它們命名也是很重要的,我們以後會用這個工程名和類名來創建這個元件的實例!後面詳細介紹.
如何改名,我就不想多說了! 我們的工程名改為Exmaple,類名為Helloword
怎樣使用工程和類
現在我們有了我們自己的工程(Example1)和類名(HelloWorld).以後我們就會在ASP代碼中使用它們的名字來引用這個元件.在ASP中我們就這樣引用,如下:
Set ObjReference = Server.CreateObject("ProjectName.ClassName")
對於我們工程的引用就是: Set ObjReference = Server.CreateObject("Example1.HelloWorld") 現在我們就能用ObjReference來調用我們在元件中所創建的函數,子程序.下面我們會來寫一個SayHello的子程序, 我們執行它的代碼如下:
〈% Set ObjReference = Server.CreateObject("Example1.HelloWorld") ObjReference.SayHello %>
為了在Helloword類中使用ASP的方法,你必須在此類中寫一個OnStartPage 子函數.如下:
Public Sub OnStartPage(PassedScriptingContext As ScriptingContext) Set MyScriptingContext = PassedScriptingContext End Sub
現在,無論什麼時候用戶訪問一個帶有本元件的ASP文件,IIS就會把ScriptingContext傳送給我們的對象請我們使用.這個ScriptingContext包括了全部的ASP方法和屬性.實現上,這使得我們有能力訪問所有ASP的對象.看下面的代碼:
Public Sub OnStartPage(PassedScriptingContext As ScriptingContext) Set MyScriptingContext = PassedScriptingContext Set MyApplication = MyScriptingContext.Application Set MyRequest = MyScriptingContext.Request Set MyResponse = MyScriptingContext.Response Set MyServer = MyScriptingContext.Server Set MySession = MyScriptingContext.Session End Sub
以後我們就能用在VB中用MyApplication 來代替ASP中的Application,同理可以代替Request,Server.....,不過我們來是要在 OnStartPage之前來申明這些變數:
Private MyScriptingContext As ScriptingContext Private MyApplication As Application Private MyRequest As Request Private MyResponse As Response Private MyServer As Server Private MySession As Session
使用ASP的對象 我們的變數現在就能像標準的ASP對象來使用了!比如,我們經常在ASP中用Request.form()來收集提交表單的數據.現在我們在我們的VB中實現這個功能,代碼如下:
用ASP中實現: 〈% MyTempVariable = Request.Form("userName") Response.Write ("you entered "& MyTempVariable & "as your user name") %>
在VB中實現:
MyTempVariable = MyRequest.Form("userName") MyResponse.Write ("you entered "& MyTempVariable & "as your user name")
通過使用MyResponse來代替Response,我們能夠使用所有Response的方法,當然,MyResponse這個名字可以隨便來取,你甚至可以就取Response. 另一件我們得注意的是,我們得在我們的建立的類中,寫上OnEndPage子函數,這個OnStartPage是相反的!OnStartPage是創建對象,OnEndPage是消毀對象.
Public Sub OnEndPage() Set MyScriptingContext = Nothing Set MyApplication = Nothing Set MyRequest = Nothing Set MyResponse = Nothing Set MyServer = Nothing Set MySession = Nothing End Sub
SayHello方法 我們來建立一個子函數,用於顯示"Holle World".這個SayHello方法只是HelloWorld這個類中一個子函數,我們以後會在ASP中用以下的顯示這個方法
〈% Set ObjReference = Server.CreateObject("Example1.HelloWorld") ObjReference.SayHello %>
SayHello的程序,很簡單的!
Public Sub SayHello() MyResponse.Write ("Hello World") End Sub
現在一個小型的元件編寫完成,剩下的工作就是編譯這個元件,在"工程"菜單中保存它,取什麼名字都可以,我們用Exmaple1.vbp吧! 然後就用在菜單中選擇"make exmaple1.dll",將其編譯成DLL文件.一個元件就真正完成了!
注意,編譯了此元件那麼你就得先把你的PWS關掉,然後再編譯此元件.否則VB就會告訴你些元件在使用中.
在ASP中使用我們的自己的元件.
當你更正了在編譯中的錯誤,成功地編譯了example1這個工程,現在你就得拿出你最喜歡的HTML編輯器來寫下下面的語句,保存為ASP文件.
〈HTML> 〈HEAD> 〈TITLE>Example 1〈/TITLE> 〈/HEAD>
〈BODY>
〈% Set ObjReference = Server.CreateObject("Example1.HelloWorld") ObjReference.SayHello %>
〈/BODY> 〈/HTML>
運行後即可看到結果:
Hello World
註冊元件
如果你想和你的朋友,鄰居分享你的元件,那麼你就得在你的系統上註冊你的元件.我們一般使用Regsvr32.exe來註冊元件.註冊後你的元件會出現在Win95/Win98的windows/system目錄中.下面是一個註冊的例子:
Regsvr32.exe C:/wwwroot/Example1/Example1.dll
|
|
加亮显示ASP文章原代码(转) 
|
加亮显示ASP文章原代码 加入时间:2000年10月29日 来源网站:中华技术网 <%@ LANGUAGE="VBSCRIPT" %> <% Option Explicit %> <% 'File: CodeBrws.asp 'Overview: This formats and writes the text of the selected page for ' the View Script Button 'This file is provided as part of the Microsoft Visual Studio 6.0 Samples
'THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT 'WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 'INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 'OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 'PURPOSE.
'Copyright (C) 1997, 1998 Microsoft Corporation, All rights reserved %> <html>
<head> <meta NAME="DESCRIPTION" CONTENT="ASP Source code browser"> <meta NAME="GENERATOR" CONTENT="Microsoft FrontPage 3.0"> <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso8859-1"> <title></title> </head>
<body BGCOLOR="#FFFFFF" TOPMARGIN="0" LEFTMARGIN="0" ALINK="#23238E" VLINK="#808080" LINK="#FFCC00"> <basefont FACE="VERDANA, ARIAL, HELVETICA" SIZE="2"><!--- DISPLAY THE COLOR LEGEND --->
<table BORDER="1"> <tr> <td WIDTH="25" BGCOLOR="#FF0000"> </td> <td><font FACE="VERDANA, ARIAL, HELVETICA" SIZE="2">ASP Script</font> </td> </tr> <tr> <td BGCOLOR="#0000FF"> </td> <td><font FACE="VERDANA, ARIAL, HELVETICA" SIZE="2">Comments</font> </td> </tr> <tr> <td BGCOLOR="#000000"> </td> <td><font FACE="VERDANA, ARIAL, HELVETICA" SIZE="2">HTML and Text</font> </td> </tr> </table>
<hr> <font FACE="VERDANA, ARIAL, HELVETICA" SIZE="2"><% OutputSource %> </font> </body> </html> <% Sub OutputSource Dim strVirtualPath, strFilename strVirtualPath = Request("Source") strFilename = Server.MapPath(strVirtualPath)
Dim FileObject, oInStream, strOutput 'Creates a file object to hold the text of the selected page Set FileObject = CreateObject("Scripting.FileSystemObject") Set oInStream = FileObject.OpenTextFile(strFilename, 1, 0, 0) 'Loop that writes each line of text in the file according to 'the PrintLine function below While NOT oInStream.AtEndOfStream strOutput = oInStream.ReadLine Call PrintLine(strOutput, fCheckLine(strOutput)) Response.Write "<BR>" Wend End Sub
' Returns the minimum number greater than 0 ' If both are 0, returns -1 Function fMin(iNum1, iNum2) If iNum1 = 0 AND iNum2 = 0 Then fMin = -1 ElseIf iNum2 = 0 Then fMin = iNum1 ElseIf iNum1 = 0 Then fMin = iNum2 ElseIf iNum1 < iNum2 Then fMin = iNum1 Else fMin = iNum2 End If End Function
Function fCheckLine (ByVal strLine) Dim iTemp, iPos fCheckLine = 0 iTemp = 0
iPos = InStr(strLine, "<" & "%") If fMin(iTemp, iPos) = iPos Then iTemp = iPos fCheckLine = 1 End If
iPos = InStr(strLine, "%" & ">") If fMin(iTemp, iPos) = iPos Then iTemp = iPos fCheckLine = 2 End If
iPos = InStr(1, strLine, "<" & "SCRIPT", 1) If fMin(iTemp, iPos) = iPos Then iTemp = iPos fCheckLine = 3 End If
iPos = InStr(1, strLine, "<" & "/SCRIPT", 1) If fMin(iTemp, iPos) = iPos Then iTemp = iPos fCheckLine = 4 End If
iPos = InStr(1, strLine, "<" & "!--", 1) If fMin(iTemp, iPos) = iPos Then iTemp = iPos fCheckLine = 5 End If
iPos = InStr(1, strLine, "-" & "->", 1) If fMin(iTemp, iPos) = iPos Then iTemp = iPos fCheckLine = 6 End If
End Function
Sub PrintHTML (ByVal strLine) Dim iPos, iSpaces, i iSpaces = Len(strLine) - Len(LTrim(strLine)) i = 1 'Correct for tabs While Mid(Strline, i, 1) = Chr(9) iSpaces = iSpaces + 5 i = i + 1 Wend 'Insert spaces If iSpaces > 0 Then For i = 1 to iSpaces Response.Write(" ") Next End If iPos = InStr(strLine, "<") If iPos Then Response.Write(Left(strLine, iPos - 1)) Response.Write("<") strLine = Right(strLine, Len(strLine) - iPos) Call PrintHTML(strLine) Else Response.Write(strLine) End If End Sub
Sub PrintLine (ByVal strLine, iFlag) Dim iPos Select Case iFlag Case 0 Call PrintHTML(strLine)
Case 1 iPos = InStr(strLine, "<" & "%") Call PrintHTML(Left(strLine, iPos - 1)) Response.Write("<FONT COLOR=#ff0000>") Response.Write("<%") strLine = Right(strLine, Len(strLine) - (iPos + 1)) Call PrintLine(strLine, fCheckLine(strLine))
Case 2 iPos = InStr(strLine, "%" & ">") Call PrintHTML(Left(strLine, iPos -1)) Response.Write("%>") Response.Write("</FONT>") strLine = Right(strLine, Len(strLine) - (iPos + 1)) Call PrintLine(strLine, fCheckLine(strLine))
Case 3 iPos = InStr(1, strLine, "<" & "SCRIPT", 1) Call PrintHTML(Left(strLine, iPos - 1)) Response.Write("<FONT COLOR=#0000ff>") Response.Write("<SCRIPT") strLine = Right(strLine, Len(strLine) - (iPos + 6)) Call PrintLine(strLine, fCheckLine(strLine))
Case 4 iPos = InStr(1, strLine, "<" & "/SCRIPT>", 1) Call PrintHTML(Left(strLine, iPos - 1)) Response.Write("</SCRIPT>") Response.Write("</FONT>") strLine = Right(strLine, Len(strLine) - (iPos + 8)) Call PrintLine(strLine, fCheckLine(strLine))
Case 5 iPos = InStr(1, strLine, "<" & "!--", 1) Call PrintHTML(Left(strLine, iPos - 1)) Response.Write("<FONT COLOR=#0000ff>") Response.Write("<!--") strLine = Right(strLine, Len(strLine) - (iPos + 3)) Call PrintLine(strLine, fCheckLine(strLine))
Case 6 iPos = InStr(1, strLine, "-" & "->", 1) Call PrintHTML(Left(strLine, iPos - 1)) Response.Write("-->") Response.Write("</FONT>") strLine = Right(strLine, Len(strLine) - (iPos + 2)) Call PrintLine(strLine, fCheckLine(strLine))
Case Else Response.Write("Function Error -- Please contact the administrator.") End Select End Sub %>
|
|
在VBScript中使用类 
|
前言
首先,在我进入实质性主题并解释如何建立类之前,我希望保证你知道“对象”。虽然你可以在程序中使用对象而不用知道其正确的规则,但我并不建议如此!对于对象的初学者,接下来的部分将让你了解其概念及内容。已经了解面向对象编程(OOP)的读者可以跳过这章节。
导论
l “对象是什么?”——对象通常代表某种实体,主要是一个变量和函数的集合。
l “实体是什么?”——字面上说,实体是一个“事物”,我的意思是一个概念或者任何一个物体。例如,一辆汽车是一个实体,因为它是一个物体。你公司销售部门销售产品也是一个实体,当然,你也可以将其拆开来看,销售人员、客户、产品等都是实体。
让我们更深入的来看“销售”这个实体(对象)。为了使你更准确地有一个销售的“映像”,你需要知道客户买了什么,是哪个客户,谁是销售人员等等……这看来是一个简单的事件,但假设所有信息是存储在单独的数据库表中的,那么当你需要获得某个销售过程所有相关信息时,你必须在你的数据库中做多次独立查询,再将所有的数据集拢。有没有更简便的办法而一次获得销售的所有信息呢?“对象”。
在对象中,你可以植入代码以从其他表中获得数据,你也可以保存对象属性的所有信息,这样,你可以轻松地使用代码管理你的销售数据。例如:
'Open the database connection Set objConn = Server.CreateObject("ADODB.Connection") objConn.Open "MyDSN"
'Create the recordset object Set objRS = Server.CreateObject("ADODB.Recordset")
'Define the SQL query strComplexSQLQuery = "SELECT C.Name, S.Name FROM Customers C, " & _ "Salespeople S, Sales Sl WHERE Sl.CustomerID=C.ID AND " & _ "Sl.SalespersonID=S.ID AND Sl.ID=" & strIDOfThisSale & ";"
'Open the recordset objRS.Open strComplexSQLQuery, objConn, adOpenForwardOnly, _ adLockReadOnly, adCmdText
'Take the customer and sales person names from the recordset strCustomerName = objRS(0) strSalesPersonName = objRS(1)
'Tidy up the objects objRS.Close objConn.Close Set objRS = Nothing Set objConn = Nothing
'Output the data Response.Write "This sale was made by " & strSalesPersonName & _ " to " & strCustomerName
可以使用“对象”来替代:
'Create the "Sale" object Set objSale = New Sale
'Lookup the correct sale objSale.ID = strIDOfThisSale
'Output the data Response.Write "This sale was made by " & objSale.SalesPersonName & _ " to " & objSale.CustomerName
'Tidy up the objects objSale.Close Set objSale = Nothing 如果你使用“Sale”对象做比打印更多的事,可以让你省去很多的打字时间。
计算中,对象包括“属性”和“方法”。属性主要是储存在对象中的一个变量,其用法与变量相同。唯一的区别在于参数赋值为:strMyVar = "This is a string variant", 而对象属性为 objObject.Property="This is a string variant"。这点非常简单而有用处。方法可以理解为植入对象中的函数与过程,可以使用strMyVar = objObject.MethodName(strMyVar)来代替strMyVar =FunctionName(strMyVar)。写法不同,但功能相同。属性的一个例子是对象Response中的ExpireAbsolute,Response.ExpiresAbsolute = CDate("1 September 1999")。方法的一个例子是对象Response中的Write方法,Response.Write "Hello world!"。
VBScript的一个新特性就是其可以创建新的对象而不需要求诸于花销时间都极大的编译器。我将向读者展示如何创建对象的类,并希望提供一个良好的开端。
创建对象
在VBScript中创建对象类型(类)时,你首先要知道,这真的很容易!我在一个下午自学,只是阅读了Microsof VB Script 的参考书,但必须承认,这书不是最容易阅读的文档。
初学者需要安装VBScript 5.0引擎,可以在Microsoft's Scripting Site下载。
我们来看代码。类的定义与函数和子过程非常类似。起始行为Class <MyClassName>,结尾是End Class,所有的对象定义写在中间部门。现在我们可以用所学的来建立第一个类,不实现任何功能的类。
Class 4GuysTestObject
End Class
这看上去不是那么回事,但当你写入下面的代码后,你将创建一个对象的实例:
Dim objTestObject
Set objTestObject = New 4GuysTestObject
Set objTestObject = Nothing
显然,我们现在还不能用对象做任何事,现在我将解释如何在对象中定义属性和方法。
使用对象可以做的最基础的,是建立一组数据。例如,假如要将时间、日期及视频程序标题建立在一起,你可以创建一个包含属性“StartTime”, “ProgramDate”和“ProgramTitle”的对象。代码如下:
Class TVProgram
Public StartTime
Public ProgramDate
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate
代码工作的方式是,我们定义StartTime,ProgramDate和ProgramTitle为类TVProgram的属性。这样,这些属性就像其他变量一样来处理,没有设置值则不会执行代码。属性名字前的Public字段有其真实含义,而且非常重要。如果你不特指一个方法或属性为public或private,系统默认值为public,但最好养成定义任何值的良好书写习惯(也方便你之后自己的阅读)。
上面程序的结果大致如下(决定于你的本地服务器配置):
The Jerry Springer Show is on at 5:30pm on 17/09/99.
我在英国,所以日期现实如上。不论你跑什么工程,它的效果都不错,但只有你开始使用其他对象的功能,为你可能需要的所有信息和功能,创建一个完美的接口,以支持你所建对象包围的实体,你才会体会到对象的真正实力。
现在,如果你不喜欢上面例子显示日期的方法,而希望以同一种格式现实日期,也没有不要在引用每个ProgramDate属性时加FormatDateTime(),你只需要将此类代码植入属性本身。
这样需要用另一种方法定义属性。同样,我们将使用ProgramDate为外部可见属性,但因为ProgramDate属性将成为一个函数而不是静态值,我们将实际日期保存在另一个属性中internal_ProgramDate。
Class TVProgram Public StartTime
Public internal_ProgramDate
Public Property Get ProgramDate ProgramDate = Day(internal_ProgramDate) & _ " " & MonthName(Month(internal_ProgramDate)) & _ " " & Year(internal_ProgramDate) End Property
Public ProgramTitle End Class
Dim objTVShow Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30") objTVShow.internal_ProgramDate = DateSerial(1999,9,17) objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _ objTVShow.StartTime & " on " & objTVShow.ProgramDate & "."
程序的结果如下:
The Jerry Springer Show is on at 5:30pm on 17 September 1999. 我们来分析一下(2)中的程序:
Class TVProgram
Public StartTime
Public internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & _
" " & MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.internal_ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate & "."
当调用对象的属性ProgramDate时,实际上执行了函数ProgramDate,即如上定义的函数,而很快你也将习惯这种在声明部分使用Public或Private关键字的方式。关键字“Property”,告知了编译器如同调用属性一样在外部调用函数。接着的“Get”,表明该函数是输出还是获得一个值。
Get的意思是“允许外部代码去‘获取’一个值”,与其类似的关键字还有“Let”和“Set”,但这两个比较复杂,因而我们以后再讨论。
接下去的代码看来有点难度的,给objectname.internal_ProgramDate赋值并通过objectname.ProgramDate来调用它。如果可以使用相同关键字同时为其赋值并获得它的值不是更好吗?当然,那也可以。
如果定义Get和Let属性的名称相同,可以将它们当作对象相同的属性,但这只限于它们定义了相同数量的成员。(以下代码看来不太相同,仅作为实例参考)
Class TVProgram
Public StartTime
Public internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & " " _
& MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
internal_ProgramDate = CDate(varDateIn)
End Property
Public ProgramTitle
End Class
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.ProgramDate = "17 Sept 99"
objTVShow.ProgramTitle = "The Jerry Springer Show"
Response.Write objTVShow.ProgramTitle & " is on at " & _
objTVShow.StartTime & " on " & objTVShow.ProgramDate & "."
以上代码中Let的声明部分看来似乎是一个多余的元素,当我第一次看到时研究了很长时间。每次我使用“0”作为变量用在每个属性上,我总是得到这个错误信息,“元素数量必须相等”。“它们确实相等!”抓狂之后,我回过头去看程序才觉得自己的愚蠢!:)
原因是,当你试图为ProgramDate赋值时,你会使用这样一行程序:
objTVShow.ProgramDate = dtmMyDate
为了方便,等号右边的值(这里指dtmMyDate)作为了一个程元赋给了函数。因此编译器可能会认为在Get ProgramDate行有0程元,而Let ProgramDate却多一个!分配的值总是被略过而作为属性的最后一个程元,所以即使你使用其他程元,所赋的值总是作为最后一个程元。
现在看程序。无论通过ProgramDate设置日期为文本形式,还是用internal_ProgramDate译成日期变量,程序都没有问题。但能不能只使用一个入口呢?
如果internal_ProgramDate只能在内部有效,而使用Let ProgramDate检查传输的数据类型,我们就可以作出选择。例如:
Class TVProgram
Public StartTime
Private internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & " " & _
MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
If IsDate(varDateIn) Then
internal_ProgramDate = varDateIn
Else
'Place some error handling code in here.
End If
End Property
Public ProgramTitle
End Class
并同样声明StartTime属性:
Class TVProgram
Private internal_StartTime
Public Property Get StartTime
StartTime = Hour(internal_StartTime) & ":" _
& Minute(internal_StartTime)
End Property
Public Property Let StartTime(ByVal varTimeIn)
If IsDate(varTimeIn) Then
internal_StartTime = varTimeIn
End If
End Property
Private internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & " " _
& MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
If IsDate(varDateIn) Then
internal_ProgramDate = varDateIn
End If
End Property
Public ProgramTitle
End Class
...
现在的代码离我们想要的还是有些不太实用,我们将在其他页使用类TVProgram,因此最好将其独立定义,以便所有也面都可以调用。我们将在第四部分讨论这点。
现在的代码离我们想要的还是有些不太实用,我们将在其他页使用类TVProgram,因此最好将其独立定义,以便所有也面都可以调用。创建一个ASP页面,并命名为TVProgramClass.asp,我们在其中定义类TVProgram。
--TVProgramClass.asp--
<%
Class TVProgram
Private internal_StartTime
Public Property Get StartTime
StartTime = Hour(internal_StartTime) & _
":" & Minute(internal_StartTime)
End Property
Public Property Let StartTime(ByVal varTimeIn)
If IsDate(varTimeIn) Then
internal_StartTime = varTimeIn
End If
End Property
Private internal_ProgramDate
Public Property Get ProgramDate
ProgramDate = Day(internal_ProgramDate) & _
" " & MonthName(Month(internal_ProgramDate)) & _
" " & Year(internal_ProgramDate)
End Property
Public Property Let ProgramDate(ByVal varDateIn)
If IsDate(varDateIn) Then
internal_ProgramDate = varDateIn
End If
End Property
Public ProgramTitle
End Class
%>
这样就可以在任何ASP中调用我们定义的类了,语法如下:
<!-- #include virtual="TVProgramClass.asp" --> <%
Dim objTVShow
Set objTVShow = New TVProgram
objTVShow.StartTime = CDate("17:30")
objTVShow.ProgramDate = DateSerial(1999,9,17)
objTVShow.ProgramTitle = "The Jerry Springer Show"
%>
<%= objTVShow.ProgramTitle %> is on at <%= objTVShow.StartTime %> on <%= objTVShow.ProgramDate %>.
这里有一个建议。如果你重命名你的包含文件.asp,并保证所有重要代码都在<CODE><% ... %>< CODE>中,那么就算有人猜到了你包含文件的文件名,也没办法看见里面的内容!
|
|
网页制作必備之初級代碼 
|
1.获得系统时间: <%=now()%>
2.取得来访用的IP: <%=request.servervariables("remote_host")%>
3.获得系统,浏览器版本: <script> window.document.write("版本:"+navigator.appName+navigator.appVersion+" browser.") </script>
4.去除IE混动条: <body scroll="no"> <body style="overflow-y:hidden">
5.进入网站,跳出广告: <script language="javascript"> <!-- <!-- 注意更改文件所在路径--> window.open(''http://www.******.com','''',''height=200,width=300,top=0,left=30''); // --> </script>
6.随机数: <%randomize%> <%=(int(rnd()*n)+1)%> N为可改变数
7.向上混动代码: <marquee direction="up" scrolldelay="200" style="font-size: 9pt; color: #FF0000; line-height: 150%; font-style:italic; font-weight:bold" scrollamount="2" width="206" height="207" bgcolor="#FFFF00">hhhhhhhhhhhhhhhhhhh</marquee>
8.自动关闭网页: <script LANGUAGE="javascript"> <!-- setTimeout(''window.close();'', 10000); //60秒后关闭 // --> </script> <p align="center">本页10秒后自动关闭,请注意刷新页面</p>
9.随机背景音乐: <%randomize%> <bgsound src="mids/<%=(int(rnd()*60)+1)%>.mid" loop="-1">
可以修改数字,限制调用个数,我这里是60个.
10.自动刷新本页面: <script> <!-- var limit="0:10"
if (document.images){ var parselimit=limit.split(":") parselimit=parselimit[0]*60+parselimit[1]*1 } function beginrefresh(){ if (!document.images) return if (parselimit==1) window.location.reload() else{ parselimit-=1 curmin=Math.floor(parselimit/60) cursec=parselimit%60 if (curmin!=0) curtime=curmin+"分"+cursec+"秒后重刷本页!" else curtime=cursec+"秒后重刷本页!" window.status=curtime setTimeout("beginrefresh()",1000) } }
window.onload=beginrefresh file://--> </script>
11.ACCESS数据库连接: <% option explicit dim startime,endtime,conn,connstr,db startime=timer() '更改数据库名字 db="data/dvBBS5.mdb" Set conn = Server.CreateObject("ADODB.Connection") connstr="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath(db) '如果你的服务器采用较老版本Access驱动,请用下面连接方法 'connstr="driver={Microsoft Access Driver (*.mdb)};dbq=" & Server.MapPath(db) conn.Open connstr function CloseDatabase Conn.close Set conn = Nothing End function %>
12.SQL数据库连接: <% option explicit dim startime,endtime,conn,connstr,db startime=timer() connstr="driver={SQL Server};server=HUDENQ-N11T33NB;uid=sa;pwd=xsfeihu;database=dvbbs" Set conn = Server.CreateObject("ADODB.Connection") conn.Open connstr function CloseDatabase Conn.close Set conn = Nothing End function %>
13.用键盘打开网页代码: <script language="javascript"> function ctlent(eventobject) { if((event.ctrlKey && window.event.keyCode==13)||(event.altKey && window.event.keyCode==83)) { window.open('网址','','') } } </script>
这里是Ctrl+Enter和Alt+S的代码 自己查下键盘的ASCII码再换就行
14.让层不被控件复盖代码: <div z-Index:2><object ***></object></div> # 前面 <div z-Index:1><object ***></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>
15.FLASH广告代码: <object classid="clsid27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0" width="468" height="60"><param name=movie value="images/yj16d.swf"><param name=quality value=high><embed src="images/dvbanner.swf" quality=high pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash";;;; type="application/x-shockwave-flash" width="468" height="60"></embed></object>
16.VBS弹出窗口小代码: <script language=vbscript> msgbox"你还没有注册或登陆论坛","0","精品论坛" location.href = "login.asp" </script> 16.使用FSO修改文件特定内容的函数 function FSOchange(filename,Target,String) Dim objFSO,objCountFile,FiletempData Set objFSO = Server.CreateObject("scripting.FileSystemObject") Set objCountFile = objFSO.OpenTextFile(Server.MapPath(filename),1,True) FiletempData = objCountFile.ReadAll objCountFile.Close FiletempData=Replace(FiletempData,Target,String) Set objCountFile=objFSO.CreateTextFile(Server.MapPath(filename),True) objCountFile.Write FiletempData objCountFile.Close Set objCountFile=Nothing Set objFSO = Nothing End function
17.使用FSO读取文件内容的函数 function FSOFileRead(filename) Dim objFSO,objCountFile,FiletempData Set objFSO = Server.CreateObject("scripting.FileSystemObject") Set objCountFile = objFSO.OpenTextFile(Server.MapPath(filename),1,True) FSOFileRead = objCountFile.ReadAll objCountFile.Close Set objCountFile=Nothing Set objFSO = Nothing End function
18.使用FSO读取文件某一行的函数 function FSOlinedit(filename,lineNum) if linenum < 1 then exit function dim fso,f,temparray,tempcnt set fso = server.CreateObject("scripting.filesystemobject") if not fso.fileExists(server.mappath(filename)) then exit function set f = fso.opentextfile(server.mappath(filename),1) if not f.AtEndofStream then tempcnt = f.readall f.close set f = nothing temparray = split(tempcnt,chr(13)&chr(10)) if lineNum>ubound(temparray)+1 then exit function else FSOlinedit = temparray(lineNum-1) end if end if end function
19.使用FSO写文件某一行的函数 function FSOlinewrite(filename,lineNum,Linecontent) if linenum < 1 then exit function dim fso,f,temparray,tempCnt set fso = server.CreateObject("scripting.filesystemobject") if not fso.fileExists(server.mappath(filename)) then exit function set f = fso.opentextfile(server.mappath(filename),1) if not f.AtEndofStream then tempcnt = f.readall f.close temparray = split(tempcnt,chr(13)&chr(10)) if lineNum>ubound(temparray)+1 then exit function else temparray(lineNum-1) = lineContent end if tempcnt = join(temparray,chr(13)&chr(10)) set f = fso.createtextfile(server.mappath(filename),true) f.write tempcnt end if f.close set f = nothing end function
20.使用FSO添加文件新行的函数 function FSOappline(filename,Linecontent) dim fso,f set fso = server.CreateObject("scripting.filesystemobject") if not fso.fileExists(server.mappath(filename)) then exit function set f = fso.opentextfile(server.mappath(filename),8,1) f.write chr(13)&chr(10)&Linecontent f.close set f = nothing end function 21.读文件最后一行的函数 function FSOlastline(filename) dim fso,f,temparray,tempcnt set fso = server.CreateObject("scripting.filesystemobject") if not fso.fileExists(server.mappath(filename)) then exit function set f = fso.opentextfile(server.mappath(filename),1) if not f.AtEndofStream then tempcnt = f.readall f.close set f = nothing temparray = split(tempcnt,chr(13)&chr(10)) FSOlastline = temparray(ubound(temparray)) end if end function 利用FSO取得BMP,JPG,PNG,GIF文件信息(大小,宽、高等) <% '::: BMP, GIF, JPG and PNG :::
'::: This function gets a specified number of bytes from any ::: '::: file, starting at the offset (base 1) ::: '::: ::: '::: Passed: ::: '::: flnm => Filespec of file to read ::: '::: offset => Offset at which to start reading ::: '::: bytes => How many bytes to read ::: '::: ::: '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: function GetBytes(flnm, offset, bytes) Dim objFSO Dim objFTemp Dim objTextStream Dim lngSize on error resume next Set objFSO = CreateObject("scripting.FileSystemObject")
' First, we get the filesize Set objFTemp = objFSO.GetFile(flnm) lngSize = objFTemp.Size set objFTemp = nothing fsoForReading = 1 Set objTextStream = objFSO.OpenTextFile(flnm, fsoForReading) if offset > 0 then strBuff = objTextStream.Read(offset - 1) end if if bytes = -1 then ' Get All! GetBytes = objTextStream.Read(lngSize) 'ReadAll else GetBytes = objTextStream.Read(bytes) end if objTextStream.Close set objTextStream = nothing set objFSO = nothing end function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: '::: ::: '::: functions to convert two bytes to a numeric value (long) ::: '::: (both little-endian and big-endian) ::: '::: ::: '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: function lngConvert(strTemp) lngConvert = clng(asc(left(strTemp, 1)) + ((asc(right(strTemp, 1)) * 256))) end function function lngConvert2(strTemp) lngConvert2 = clng(asc(right(strTemp, 1)) + ((asc(left(strTemp, 1)) * 256))) end function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: '::: ::: '::: This function does most of the real work. It will attempt ::: '::: to read any file, regardless of the extension, and will ::: '::: identify if it is a graphical image. ::: '::: ::: '::: Passed: ::: '::: flnm => Filespec of file to read ::: '::: width => width of image ::: '::: height => height of image ::: '::: depth => color depth (in number of colors) ::: '::: strImageType=> type of image (e.g. GIF, BMP, etc.) ::: '::: ::: '::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: function gfxSpex(flnm, width, height, depth, strImageType) dim strPNG dim strGIF dim strBMP dim strType strType = "" strImageType = "(unknown)" gfxSpex = False strPNG = chr(137) & chr(80) & chr(78) strGIF = "GIF" strBMP = chr(66) & chr(77) strType = GetBytes(flnm, 0, 3) if strType = strGIF then ' is GIF strImageType = "GIF" Width = lngConvert(GetBytes(flnm, 7, 2)) Height = lngConvert(GetBytes(flnm, 9, 2)) Depth = 2 ^ ((asc(GetBytes(flnm, 11, 1)) and 7) + 1) gfxSpex = True elseif left(strType, 2) = strBMP then ' is BMP strImageType = "BMP" Width = lngConvert(GetBytes(flnm, 19, 2)) Height = lngConvert(GetBytes(flnm, 23, 2)) Depth = 2 ^ (asc(GetBytes(flnm, 29, 1))) gfxSpex = True elseif strType = strPNG then ' Is PNG strImageType = "PNG" Width = lngConvert2(GetBytes(flnm, 19, 2)) Height = lngConvert2(GetBytes(flnm, 23, 2)) Depth = getBytes(flnm, 25, 2) select case asc(right(Depth,1)) case 0 Depth = 2 ^ (asc(left(Depth, 1))) gfxSpex = True case 2 Depth = 2 ^ (asc(left(Depth, 1)) * 3) gfxSpex = True case 3 Depth = 2 ^ (asc(left(Depth, 1))) '8 gfxSpex = True case 4 Depth = 2 ^ (asc(left(Depth, 1)) * 2) gfxSpex = True case 6 Depth = 2 ^ (asc(left(Depth, 1)) * 4) gfxSpex = True case else Depth = -1 end select
else strBuff = GetBytes(flnm, 0, -1) ' Get all bytes from file lngSize = len(strBuff) flgFound = 0 strTarget = chr(255) & chr(216) & chr(255) flgFound = instr(strBuff, strTarget) if flgFound = 0 then exit function end if strImageType = "JPG" lngPos = flgFound + 2 ExitLoop = false do while ExitLoop = False and lngPos < lngSize
do while asc(mid(strBuff, lngPos, 1)) = 255 and lngPos < lngSize lngPos = lngPos + 1 loop if asc(mid(strBuff, lngPos, 1)) < 192 or asc(mid(strBuff, lngPos, 1)) > 195 then lngMarkerSize = lngConvert2(mid(strBuff, lngPos + 1, 2)) lngPos = lngPos + lngMarkerSize + 1 else ExitLoop = True end if loop ' if ExitLoop = False then Width = -1 Height = -1 Depth = -1 else Height = lngConvert2(mid(strBuff, lngPos + 4, 2)) Width = lngConvert2(mid(strBuff, lngPos + 6, 2)) Depth = 2 ^ (asc(mid(strBuff, lngPos + 8, 1)) * 8) gfxSpex = True end if
end if end function
'::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: '::: Test Harness ::: ':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
' To test, we'll just try to show all files with a .GIF extension in the root of C: Set objFSO = CreateObject("scripting.FileSystemObject") Set objF = objFSO.GetFolder("c:\") Set objFC = objF.Files response.write "<table border=""0"" cellpadding=""5"">" For Each f1 in objFC if instr(ucase(f1.Name), ".GIF") then response.write "<tr><td>" & f1.name & "</td><td>" & f1.DateCreated & "</td><td>" & f1.Size & "</td><td>" if gfxSpex(f1.Path, w, h, c, strType) = true then response.write w & " x " & h & " " & c & " colors" else response.write " " end if response.write "</td></tr>" end if Next response.write "</table>" set objFC = nothing set objF = nothing set objFSO = nothing
%>
22.点击返回上页代码: <form> <p><input TYPE="button" value="返回上一步" onCLICK="history.back(-1)"></p> </form>
23.点击刷新代码: <form> <p><input TYPE="button" value="刷新按钮一"onCLICK="ReloadButton()"></p> </form> <script language="javascript"><!-- function ReloadButton(){location.href="allbutton.htm";} // --></script>
24.点击刷新代码2: <form> <p><input TYPE="button" value="刷新按钮二" onClic="history.go(0)"> </p> </form>
<form> <p><input TYPE="button" value="打开一个网站" onCLICK="HomeButton()"></p> </form> <script language="javascript"><!-- function HomeButton(){location.href="http://nettrain.126.com";;;;} // --></script>
25.弹出警告框代码: <form> <p><input TYPE="button" value="弹出警告框" onCLICK="AlertButton()"></p> </form> <script language="javascript"><!-- function AlertButton(){window.alert("要多多光临呀!");} // --></script>
26.状态栏信息 <form> <p><input TYPE="button" value="状态栏信息" onCLICK="StatusButton()"></p> </form> <script language="javascript"><!-- function StatusButton(){window.status="要多多光临呀!";} // --></script>
27.背景色变换 <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>
28.点击打开新窗口 <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> 29.分页代码: <%''本程序文件名为:Pages.asp%> <%''包含ADO常量表文件adovbs.inc,可从"\Program Files\Common Files\System\ADO"目录下拷贝%> <!--#Include File="adovbs.inc"--> <%''*建立数据库连接,这里是Oracle8.05数据库 Set conn=Server.CreateObject("ADODB.Connection") conn.Open "Provider=msdaora.1;Data Source=YourSrcName;User ID=YourUserID;Password=YourPassword;"
Set rs=Server.CreateObject("ADODB.Recordset") ''创建Recordset对象 rs.CursorLocation=adUseClient ''设定记录集指针属性 ''*设定一页内的记录总数,可根据需要进行调整 rs.PageSize=10
''*设置查询语句 StrSQL="Select ID,姓名,住址,电话 from 通讯录 Order By ID" rs.Open StrSQL,conn,adOpenStatic,adLockReadOnly,adCmdText %> <HTML> <HEAD> <title>分页示例</title> <script language=javascript> //点击"[第一页]"时响应: function PageFirst() { document.MyForm.CurrentPage.selectedIndex=0; document.MyForm.CurrentPage.onchange(); } //点击"[上一页]"时响应: function PagePrior() { document.MyForm.CurrentPage.selectedIndex--; document.MyForm.CurrentPage.onchange(); } //点击"[下一页]"时响应: function PageNext() { document.MyForm.CurrentPage.selectedIndex++; document.MyForm.CurrentPage.onchange(); } //点击"[最后一页]"时响应: function PageLast() { document.MyForm.CurrentPage.selectedIndex=document.MyForm.CurrentPage.length-1; document.MyForm.CurrentPage.onchange(); } //选择"第?页"时响应: function PageCurrent() { //Pages.asp是本程序的文件名 document.MyForm.action='Pages.asp?Page='+(document.MyForm.CurrentPage.selectedIndex+1) document.MyForm.submit(); } </script> </HEAD> <BODY bgcolor="#ffffcc" link="#008000" vlink="#008000" alink="#FF0000"">
<%IF rs.Eof THEN Response.Write("<font size=2 color=#000080>[数据库中没有记录!]</font>") ELSE ''指定当前页码 If Request("CurrentPage")="" Then rs.AbsolutePage=1 Else rs.AbsolutePage=CLng(Request("CurrentPage")) End If
''创建表单MyForm,方法为Get Response.Write("<form method=Get name=MyForm>") Response.Write("<p align=center><font size=2 color=#008000>") ''设置翻页超链接 if rs.PageCount=1 then Response.Write("[第一页] [上一页] [下一页] [最后一页] ") else if rs.AbsolutePage=1 then Response.Write("[第一页] [上一页] ") Response.Write("[<a href=java script:PageNext()>下一页</a>] ") Response.Write("[<a href=java script:PageLast()>最后一页</a>] ") else if rs.AbsolutePage=rs.PageCount then Response.Write("[<a href=java script:PageFirst()>第一页</a>] ") Response.Write("[<a href=java script:PagePrior()>上一页</a>] ") Response.Write("[下一页] [最后一页] ") else Response.Write("[<a href=java script:PageFirst()>第一页</a>] ") Response.Write("[<a href=java script:PagePrior()>上一页</a>] ") Response.Write("[<a href=java script:PageNext()>下一页</a>] ") Response.Write("[<a href=java script:PageLast()>最后一页</a>] ") end if end if end if
''创建下拉列表框,用于选择浏览页码 Response.Write("第<select size=1 name=CurrentPage onchange=PageCurrent()>") For i=1 to rs.PageCount if rs.AbsolutePage=i then Response.Write("<option selected>"&i&"</option>") ''当前页码 else Response.Write("<option>"&i&"</option>") end if Next Response.Write("</select>页/共"&rs.PageCount&"页 共"&rs.RecordCount&"条记录</font><p>") Response.Write("</form>")
''创建表格,用于显示 Response.Write("<table align=center cellspacing=1 cellpadding=1 border=1") Response.Write(" bordercolor=#99CCFF bordercolordark=#b0e0e6 bordercolorlight=#000066>")
Response.Write("<tr bgcolor=#ccccff bordercolor=#000066>")
Set Columns=rs.Fields
''显示表头 For i=0 to Columns.Count-1 Response.Write("<td align=center width=200 height=13>") Response.Write("<font size=2><b>"&Columns(i).name&"</b></font></td>") Next Response.Write("</tr>") ''显示内容 For i=1 to rs.PageSize Response.Write("<tr bgcolor=#99ccff bordercolor=#000066>") For j=0 to Columns.Count-1 Response.Write("<td><font size=2>"&Columns(j)&"</font></td>") Next Response.Write("</tr>")
rs.movenext if rs.EOF then exit for Next
Response.Write("</table>")
END IF %> </BODY> </HTML>
40种网页常用小技巧(JavaScript) 1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border oncontextmenu=return(false)><td>no</table> 可用于Table
2. <body onselectstart="return false"> 取消选取、防止复制
3. onpaste="return false" 不准粘贴
4. oncopy="return false;" oncut="return false;" 防止复制
5. <link rel="Shortcut Icon" href="favicon.ico"> IE地址栏前换成自己的图标
6. <link rel="Bookmark" href="favicon.ico"> 可以在收藏夹中显示出你的图标
7. <input style="ime-mode:disabled"> 关闭输入法
8. 永远都会带着框架 <script language="JavaScript"><!-- if (window == top)top.location.href = "frames.htm"; //frames.htm为框架网页 // --></script>
9. 防止被人frame <SCRIPT LANGUAGE=JAVASCRIPT><!-- if (top.location != self.location)top.location=self.location; // --></SCRIPT>
10. 网页将不能被另存为 <noscript><iframe src=*.html></iframe></noscript>
11. <input type=button value=查看网页源代码 onclick="window.location = "view-source:"+ "http://www.pconline.com.cn"">
12.删除时确认 <a href="javascript:if(confirm("确实要删除吗?"))location="boos.asp?&areyou=删除&page=1"">删除</a>
13. 取得控件的绝对位置 //Javascript <script language="Javascript"> function getIE(e){ var t=e.offsetTop; var l=e.offsetLeft; while(e=e.offsetParent){ t+=e.offsetTop; l+=e.offsetLeft; } alert("top="+t+"/nleft="+l); } </script>
//VBScript <script language="VBScript"><!-- function getIE() dim t,l,a,b set a=document.all.img1 t=document.all.img1.offsetTop l=document.all.img1.offsetLeft while a.tagName<>"BODY" set a = a.offsetParent t=t+a.offsetTop l=l+a.offsetLeft wend msgbox "top="&t&chr(13)&"left="&l,64,"得到控件的位置" end function --></script>
14. 光标是停在文本框文字的最后 <script language="javascript"> function cc() { var e = event.srcElement; var r =e.createTextRange(); r.moveStart("character",e.value.length); r.collapse(true); r.select(); } </script> <input type=text name=text1 value="123" onfocus="cc()">
15. 判断上一页的来源 javascript: document.referrer
16. 最小化、最大化、关闭窗口 <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
17.屏蔽功能键Shift,Alt,Ctrl <script> function look(){ if(event.shiftKey) alert("禁止按Shift键!"); //可以换成ALT CTRL } document.onkeydown=look; </script>
18. 网页不会被缓存 <META HTTP-EQUIV="pragma" CONTENT="no-cache"> <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> <META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT"> 或者<META HTTP-EQUIV="expires" CONTENT="0">
19.怎样让表单没有凹凸感? <input type=text style="border:1 solid #000000"> 或 <input type=text style="border-left:none; border-right:none; border-top:none; border-bottom:
1 solid #000000"></textarea>
20.<div><span>&<layer>的区别? <div>(division)用来定义大段的页面元素,会产生转行 <span>用来定义同一行内的元素,跟<div>的唯一区别是不产生转行 <layer>是ns的标记,ie不支持,相当于<div>
21.让弹出窗口总是在最上面: <body onblur="this.focus();">
22.不要滚动条? 让竖条没有: <body style="overflow:scroll;overflow-y:hidden"> </body> 让横条没有: <body style="overflow:scroll;overflow-x:hidden"> </body> 两个都去掉?更简单了 <body scroll="no"> </body>
23.怎样去掉图片链接点击后,图片周围的虚线? <a href="#" onFocus="this.blur()"><img src="logo.jpg" border=0></a>
24.电子邮件处理提交表单 <form name="form1" method="post" action="mailto:****@***.com" enctype="text/plain"> <input type=submit> </form>
25.在打开的子窗口刷新父窗口的代码里如何写? window.opener.location.reload()
26.如何设定打开页面的大小 <body onload="top.resizeTo(300,200);"> 打开页面的位置<body onload="top.moveBy(300,200);">
27.在页面中如何加入不是满铺的背景图片,拉动页面时背景图不动 <STYLE> body {background-image:url(logo.gif); background-repeat:no-repeat; background-position:center;background-attachment: fixed} </STYLE>
28. 检查一段字符串是否全由数字组成 <script language="Javascript"><!-- function checkNum(str){return str.match(//D/)==null} alert(checkNum("1232142141")) alert(checkNum("123214214a1")) // --></script>
29. 获得一个窗口的大小 document.body.clientWidth; document.body.clientHeight
30. 怎么判断是否是字符 if (/[^/x00-/xff]/g.test(s)) alert("含有汉字"); else alert("全是字符");
31.TEXTAREA自适应文字行数的多少 <textarea rows=1 name=s1 cols=27 onpropertychange="this.style.posHeight=this.scrollHeight"> </textarea> 32. 日期减去天数等于第二个日期 <script language=Javascript> function cc(dd,dadd) { //可以加上错误处理 var a = new Date(dd) a = a.valueOf() a = a - dadd * 24 * 60 * 60 * 1000 a = new Date(a) alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日") } cc("12/23/2002",2) </script>
33. 选择了哪一个Radio <HTML><script language="vbscript"> function checkme() for each ob in radio1 if ob.checked then window.alert ob.value next end function </script><BODY> <INPUT name="radio1" type="radio" value="style" checked>Style <INPUT name="radio1" type="radio" value="barcode">Barcode <INPUT type="button" value="check" onclick="checkme()"> </BODY></HTML>
34.脚本永不出错 <SCRIPT LANGUAGE="JavaScript"> <!-- Hide function killErrors() { return true; } window.onerror = killErrors; // --> </SCRIPT>
35.ENTER键可以让光标移到下一个输入框 <input onkeydown="if(event.keyCode==13)event.keyCode=9">
36. 检测某个网站的链接速度: 把如下代码加入<body>区域中: <script language=Javascript> tim=1 setInterval("tim++",100) b=1 var autourl=new Array() autourl[1]="www.njcatv.net" autourl[2]="javacool.3322.net" autourl[3]="www.sina.com.cn" autourl[4]="www.nuaa.edu.cn" autourl[5]="www.cctv.com" function butt(){ document.write("<form name=autof>") for(var i=1;i<autourl.length;i++) document.write("<input type=text name=txt"+i+" size=10 value=测试中……> =》<input type=text name=url"+i+" size=40> =》<input type=button value=GO
onclick=window.open(this.form.url"+i+".value)><br>") document.write("<input type=submit value=刷新></form>") } butt() function auto(url){ document.forms[0]["url"+b].value=url if(tim>200) {document.forms[0]["txt"+b].value="链接超时"} else {document.forms[0]["txt"+b].value="时间"+tim/10+"秒"} b++ } function run(){for(var i=1;i<autourl.length;i++)document.write("<img src=http://"+autourl+"/"+Math.random()+" width=1 height=1
onerror=auto("http://"+autourl+"")>")} run()</script>
37. 各种样式的光标 auto :标准光标 default :标准箭头 hand :手形光标 wait :等待光标 text :I形光标 vertical-text :水平I形光标 no-drop :不可拖动光标 not-allowed :无效光标 help :?帮助光标 all-scroll :三角方向标 move :移动标 crosshair :十字标 e-resize n-resize nw-resize w-resize s-resize se-resize sw-resize
38.页面进入和退出的特效 进入页面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)"> 推出页面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)"> 这个是页面被载入和调出时的一些特效。duration表示特效的持续时间,以秒为单位。transition表示使用哪种特效,取值为1-23: 0 矩形缩小 1 矩形扩大 2 圆形缩小 3 圆形扩大 4 下到上刷新 5 上到下刷新 6 左到右刷新 7 右到左刷新 8 竖百叶窗 9 横百叶窗 10 错位横百叶窗 11 错位竖百叶窗 12 点扩散 13 左右到中间刷新 14 中间到左右刷新 15 中间到上下 16 上下到中间 17 右下到左上 18 右上到左下 19 左上到右下 20 左下到右上 21 横条 22 竖条 23 以上22种随机选择一种
39.在规定时间内跳转 <META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">
40.网页是否被检索 <meta name="ROBOTS" content="属性值"> 其中属性值有以下一些: 属性值为"all": 文件将被检索,且页上链接可被查询; 属性值为"none": 文件不被检索,而且不查询页上的链接; 属性值为"index": 文件将被检索; 属性值为"follow": 查询页上的链接; 属性值为"noindex": 文件不检索,但可被查询链接; 属性值为"nofollow": 文件不被检索,但可查询页上的链接。 转自: http://www.zhanling.com/zhanling/qiu/blogview.asp?logID=88&cateID=3 |
|
ASP应用之模板采用
|
所以,梦想着那么大段的程序代码变成几个简单的字符代替,这样只要设计好页面把该功能插入就OK了。其实这也简单,只需将实现该功能的程序代码做成子程序,然后主页调用就可以了。
很多时候,在博客中国,你会选择到很多的模板,甚至有可能自己来设计;或者采用猪飞飞BLOG的各大站长都将其站点改得不近相同……这些,我们都归功于ASP采用模板的功能。
那下面偶就借花献佛,将模板拿来分析,以馈各位朋友。
首先,模板需要在线修改,则应采用数据库保存模板代码
所谓的模板,就是设计完工的标准的HTML代码,其中需要由程序实现的功能部分将采用特殊字符串代替。然,这些特殊字符串需要在显示的时候被编译为对应的功能。
2,假设第一模板内容代码
将下列代码拷贝到m_html字段中
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>testmb</title>
</head>
<body leftmargin="0" topmargin="0">
<table width="100%" height="100%" border="0" cellpadding="5" cellspacing="2">
<tr align="right" bgcolor="#CCCCCC">
<td height="20" colspan="2">$cntoplt;/td>
</tr>
<tr valign="top">
<td width="25%" bgcolor="#e5e5e5">$cnleftlt;/td>
<td width="74%" bgcolor="#f3f3f3">$cnrightlt;/td>
</tr>
</table>
</body>
</html>
注意$cntop$、$cnleft$、$cnright$,它们将要实现某些具体的程序功能
3,建立数据库连接文件conn.asp
<%
set conn= Server.CreateObject("ADODB.Connection")
connstr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="&Server.MapPath("testmb.mdb")
conn.Open connstr
%>
4,建立特殊字符串转换所需要的库文件lib.asp
该文件的主要作用是将实现某些功能的ASP程序做成字程序,以方便调用。
<%
dim topcode
sub cntop()
topcode="现在时间是:"
topcode=topcode&now()
end sub
dim leftcode,i
sub cnleft()
for i = 1 to 5
leftcode=leftcode&"<p>cnbruce.com"
next
end sub
dim rightcode
sub cnright()
for i = 1 to 9
rightcode=rightcode&"<hr color="&i&i&i&i&i&i&">"
next
end sub
%>
5,最后,调用数据库中的模板代码,将特殊字符串转换。
<!--#include file="conn.asp" -->
<!--#include file="lib.asp" -->
<%
sql="select * from moban where m_id=1"
set rs=Server.CreateObject("adodb.recordset")
rs.open sql,conn,1,1
mb_code=rs("m_html")
rs.close
set rs=nothing
cntop()
mb_code=replace(mb_code,"$cntop$",topcode)
cnleft()
mb_code=replace(mb_code,"$cnleft$",leftcode)
cnright()
mb_code=replace(mb_code,"$cnright$",rightcode)
response.write mb_code
%>
该页主要作用是将模板代码进行显示,并将其中的特殊代码转变为相对应子程序功能。
至此,ASP的模板功能基本完成,剩下的就是:建立具备编辑模板功能的程序页面,将库文件改变为自己所需要程序功能……
|
|
插入Access记录后马上得到自动编号值的方法
|
首先须保证获得记录集的方式支持bookmark属性,如1,3
插入一条带自动编号字段的记录后,获取该记录的bookmark属性值
temp = rs.bookmark
然后
rs.bookmark = temp
试试!!
Response.write rs.Fields("ID"). |
|
ASP中生成静态页面技术
|
<!--#include file="conn.asp"--> <% dim str function menu(id) set rs=server.CreateObject("adodb.recordset") sql="select * from menu where id1="&id&" order by url,id" rs.open sql,conn,1,1 str=str+"<table border='0' cellspacing='0' cellpadding='0'>"+chr(13) i=1 while not rs.eof ChildCount=conn.execute("select count(*) from menu where id1="&rs("id"))(0) if ChildCount=0 then if i=rs.recordcount then menutype="file1" else menutype="file" end if menuname="<a href='"&rs("url")&"' target='_blank'>"&rs("menuname")&"</a>" onmouseup="" else if i=rs.recordcount then menutype="menu3" listtype="list1" onmouseup=" onMouseUp=change1('a"&rs("id")&"','b"&rs("id")&"');" else menutype="menu1" listtype="list" onmouseup=" onMouseUp=change2('a"&rs("id")&"','b"&rs("id")&"');" end if menuname=rs("menuname") end if str=str+"<tr><td id='b"&rs("id")&"' class='"&menutype&"'"&onmouseup&">"&menuname&"</td></tr>"+chr(13) if ChildCount>0 then str=str+"<tr id='a"&rs("id")&"' style='display:none'><td class='"&listtype&"'>"+chr(13) menu(rs("id")) str=str+"</td></tr>"+chr(13) end if rs.movenext i=i+1 wend str=str+"</table>"+chr(13) rs.close set rs=nothing end function
menu(0)
set fso=server.CreateObject("scripting.filesystemobject") set f1=fso.opentextfile(server.MapPath("demo.htm"),2,true) f1.write("<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>") f1.write("<html>") f1.write("<head>") f1.write("<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>") f1.write("<title>哈哈~~~!这回速度超快了吧?</title>") f1.write("<meta name='keywords' content='asp2004,树,菜单,无限级'>") f1.write("<meta name='author' content='小灰,quxiaohui_0@163.com'>") f1.write("<link href='style.css' rel='stylesheet' type='text/css'>") f1.write("<script language='javascript' src='function.js'></script>") f1.write("</head>") f1.write("<body>") f1.write("<a href='http://asp2004.net' target='_blank'>http://asp2004.net</a>提供最新下载《<a href='menu.asp'>管理</a>》<br>")
f1.write(str)
f1.write("</body>") f1.write("</html>") f1.close set fso=nothing
response.Redirect("demo.htm") %> 演示:http://asp2004.net/temp/treemenu/menu.asp 源代码下载:http://asp2004.net/temp/treemenu.rar |
|
XMLHTTP抓取数据时乱码问题解决
|
CSDN原帖: http://community.csdn.net/Expert/topic/3316/3316086.xml?temp=.2790033
内码问题.用这段代码的吧,我已经改得很精简了. '使用XMLHTTP抓取地址并进次内容处理 Function GetBody(Url) Dim objXML On Error Resume Next Set objXML = CreateObject("Microsoft.XMLHTTP") With objXML .Open "Get", Url, False, "", "" .Send GetBody = .ResponseBody End With GetBody=BytesToBstr(GetBody,"GB2312") Set objXML = Nothing End Function '使用Adodb.Stream处理二进制数据 Function BytesToBstr(strBody,CodeBase) dim objStream set objStream = Server.CreateObject("Adodb.Stream") objStream.Type = 1 objStream.Mode =3 objStream.Open objStream.Write strBody objStream.Position = 0 objStream.Type = 2 objStream.Charset = CodeBase BytesToBstr = objStream.ReadText objStream.Close set objStream = nothing End Function
|
|
利用XMLHTTP无刷新添加数据之Post篇
|
我们传统的提交数据的方法都是用<Form>来实现的. <Form>标记中的Method属性确定了表单元素的数据在发送到服务器时, 如何对HTTP请求信息进行打包.
Method 属性可以使用的方法 Method属性 发送表单元素的方式 读取数据的Request集合 Get 标识在URL的最后 QueryString Post 在HTTP请求的主体内(HTTP请求的自由区域) Form
这篇文章用XMLHTTP来实现Form的Method=Post.
ClientPost.htm
<script language="JavaScript"> function AddDataPost(sUserId,sUserName) { /* *--------------- AddDataPost(sUserId,sUserName) ----------------- * AddDataPost(sUserId,sUserName) * 功能:通过XMLHTTP添加数据.相当于Form的Method=Post. * 参数:sUserId,字符串,发送条件. * 参数:sUserName,字符串,发送条件. * 实例:AddDataPost(document.all.userid.value,document.all.username.value); * author:wanghr100(灰豆宝宝.net) * update:2004-5-30 14:46 *--------------- AddDataPost(sUserId,sUserName) ----------------- */ var oBao = new ActiveXObject("Microsoft.XMLHTTP"); //特殊字符:+,%,&,=,?等的传输解决办法. //Update:2004-6-1 12:22 //escape(sUserId),escape(sUserName); sUserId = escape(sUserId); sUserName = escape(sUserName); var userInfo = "userid="+sUserId+"&username="+sUserName; oBao.open("POST","Server.asp",false); oBao.setRequestHeader("Content-Type","application/x-www-form-urlencoded") oBao.send(userInfo); //清空输入框数据. document.all.userid.value=""; document.all.username.value=""; //服务器端处理返回的是经过escape编码的字符串. alert(unescape(oBao.responseText)) } </script> <input type="button" onclick="AddDataPost(document.all.userid.value,document.all.username.value)" value="AddDataPost"><br> userid:<input type="text" name="userid"><br> username:<input type="text" name="username">
Server.asp 服务器端处理.
<% @Language="JavaScript" %> <% function OpenDB(sdbname) { /* *--------------- OpenDB(sdbname) ----------------- * OpenDB(sdbname) * 功能:打开数据库sdbname,返回conn对象. * 参数:sdbname,字符串,数据库名称. * 实例:var conn = OpenDB("database.mdb"); * author:wanghr100(灰豆宝宝.net) * update:2004-5-12 8:18 *--------------- OpenDB(sdbname) ----------------- */ var connstr = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source="+Server.MapPath(sdbname); var conn = Server.CreateObject("ADODB.Connection"); conn.Open(connstr); return conn; } var sResult = ""; var oConn = OpenDB("data.mdb"); //相当于Form的Method=Post. //相当于Form的Method=Post. //特殊字符:+,%,&,=,?等的传输解决办法.客户端传输过来是经过escape编码的. //所以服用器端应该先unescape解码. //Update:2004-6-1 12:22 //unescape(Request.Form("userid"))..... var userid = unescape(Request.Form("userid")); var username = unescape(Request.Form("username")); sResult = "userid:"+userid+"\nusername:"+username+"\n 添加成功." var sql = "Insert into users(userid,username)Values('"+userid+"','"+username+"')"; oConn.Execute(sql); Response.Write(escape(sResult)); %>
数据库设计 data.mdb 表users. 字段 id 自动编号 userid 文本 username 文本
表:users 数据: id userid username
|
|
利用XMLHTTP无刷新添加数据之Get篇
|
我们传统的提交数据的方法都是用<Form>来实现的. <Form>标记中的Method属性确定了表单元素的数据在发送到服务器时, 如何对HTTP请求信息进行打包.
Method 属性可以使用的方法 Method属性 发送表单元素的方式 读取数据的Request集合 Get 标识在URL的最后 QueryString Post 在HTTP请求的主体内(HTTP请求的自由区域) Form
这篇文章用XMLHTTP来实现Form的Method=Get.
ClientGet.htm
<script language="JavaScript"> function AddDataGet(sUserId,sUserName) { /* *--------------- AddDataGet(sUserId,sUserName) ----------------- * AddDataGet(sUserId,sUserName) * 功能:通过XMLHTTP添加数据.相当于Form的Method=Get. * 参数:sUserId,字符串,发送条件. * 参数:sUserName,字符串,发送条件. * 实例:AddDataGet(document.all.userid.value,document.all.username.value); * author:wanghr100(灰豆宝宝.net) * update:2004-5-30 14:46 *--------------- AddDataGet(sUserId,sUserName) ----------------- */ var oBao = new ActiveXObject("Microsoft.XMLHTTP"); //特殊字符:+,%,&,=,?等的传输解决办法.用escape编码. //Update:2004-6-1 12:22 //escape(sUserId),escape(sUserName); oBao.open("POST","Server.asp?userid="+escape(sUserId)+"&username="+escape(sUserName),false); oBao.send(); //清空输入框数据. document.all.userid.value=""; document.all.username.value=""; //服务器端处理返回的是经过escape编码的字符串. alert(unescape(oBao.responseText)) } </script> <input type="button" onclick="AddDataGet(document.all.userid.value,document.all.username.value)" value="AddDataGet"><br> userid:<input type="text" name="userid"><br> username:<input type="text" name="username">
Server.asp 服务器端处理.
<% @Language="JavaScript" %> <% function OpenDB(sdbname) { /* *--------------- OpenDB(sdbname) ----------------- * OpenDB(sdbname) * 功能:打开数据库sdbname,返回conn对象. * 参数:sdbname,字符串,数据库名称. * 实例:var conn = OpenDB("database.mdb"); * author:wanghr100(灰豆宝宝.net) * update:2004-5-12 8:18 *--------------- OpenDB(sdbname) ----------------- */ var connstr = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source="+Server.MapPath(sdbname); var conn = Server.CreateObject("ADODB.Connection"); conn.Open(connstr); return conn; } var sResult = ""; var oConn = OpenDB("data.mdb"); //相当于Form的Method=Get. //相当于Form的Method=Get. //特殊字符:+,%,&,=,?等的传输解决办法.客户端传输过来是经过escape编码的. //所以服用器端应该先用unescape解码. //Update:2004-6-1 12:22 //unescape(Request.QueryString("userid"))..... var userid = unescape(Request.QueryString("userid")); var username = unescape(Request.QueryString("username")); sResult = "userid:"+userid+"\nusername:"+username+"\n 添加成功." var sql = "Insert into users(userid,username)Values('"+userid+"','"+username+"')"; oConn.Execute(sql); Response.Write(escape(sResult)); %>
数据库设计 data.mdb 表users. 字段 id 自动编号 userid 文本 username 文本
表:users 数据: id userid username |
|
使用ASP生成HTML文件
|
'共有两个页面index.htm是首页.程序比较简单,主要是用了ASP里的文件操作对象。
index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Untitled Document</title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> </head>
<body> <table width="770" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td><form name="form1" method="post" action="send.asp"> <table width="100%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCFFFF"> <tr> <td height="20"><div align="center">发送消息</div></td> </tr> <tr> <td><div align="center"> <textarea name="msg" cols="100" rows="6"></textarea> </div></td> </tr> <tr> <td><div align="center"> <input type="submit" name="Submit" value="Submit"> <input type="reset" name="Submit2" value="Reset"> </div></td> </tr> </table> </form></td> </tr> </table> </body> </html> '//send.asp
<% function chan_time(shijian)'转换日期时间函数 s_year=year(shijian) if len(s_year)=2 then s_year="20"&s_year s_month=month(shijian) if s_month<10 then s_month="0"&s_month s_day=day(shijian) if s_day<10 then s_day="0"&s_day s_hour=hour(shijian) if s_hour<10 then s_hour="0"&s_hour s_minute=minute(shijian) if s_minute<10 then s_minute="0"&s_minute chan_time=s_year & s_month & s_day & s_hour & s_minute end function
function chan_data(shijian) '转换日期时间函数 s_year=year(shijian) if len(s_year)=2 then s_year="20"&s_year s_month=month(shijian) if s_month<10 then s_month="0"&s_month s_day=day(shijian) if s_day<10 then s_day="0"&s_day chan_data=s_year & s_month & s_day end function
function chan_file(shijian)'转换日期时间函数 s_month=month(shijian) if s_month<10 then s_month="0"&s_month s_day=day(shijian) if s_day<10 then s_day="0"&s_day s_hour=hour(shijian) if s_hour<10 then s_hour="0"&s_hour s_minute=minute(shijian) if s_minute<10 then s_minute="0"&s_minute s_ss=second(shijian) if s_ss<10 then s_ss="0"&s_ss chan_file = s_month & s_day & s_hour & s_minute & s_ss end function top="<html><head><title>news</title></head><body>" botom="</body></html>" msg=request.Form("msg") msg=replace(msg,vbcrlf,"") msg=replace(msg,chr(9),"") msg=replace(msg," "," ") msg=replace(msg,"\r\n","<br>") msg=replace(msg,"\n","<br>") msg=top&msg&botom Set fs=Server.CreateObject("Scripting.FileSystemObject") all_tree2=server.mappath("news")&"\"&chan_data(now) if (fs.FolderExists(all_tree2)) then'判断今天的文件夹是否存在 else fs.CreateFolder(all_tree2) end if pass=chan_file(now) randomize '使用系统计时器来初始化乱数产生器 pass=rnd(pass) pass=get_pass(pass) pass=left(pass,10)
file1=pass files=file1&".txt" filez=all_tree2&"\"&files
set ts = fs.createtextfile(filez,true) '写文件 for z=1 to len(msg) write_now=mid(msg,z,1) ts.write(write_now) next ' ts.writeline(all_msg) ts.close set ts=nothing '文件生成
if err.number<>0 or err then%> <script language="javascript"> alert("不能完成") </script> <%else%> <script language="javascript"> alert("已完成") history.back(); </script> <%end if Set MyFile = fs.GetFile(filez) all_tree2=server.mappath("news")&"\"&chan_data(now) if (fs.FolderExists(all_tree2)) then else fs.CreateFolder(all_tree2) end if MyFile.name= left(MyFile.name,len(MyFile.name)-4)&".htm" set MyFile=nothing set fs=nothing set fdir=nothing function get_pass(pass)
pass=cstr(pass) pass=replace(pass," ","") pass=replace(pass," ","") pass=replace(pass,"-","") pass=replace(pass," ","") pass=replace(pass,":","") pass=replace(pass,".","") pass=replace(pass,"+","") pass=replace(pass,"_","") pass=replace(pass,"<","") pass=replace(pass,">","") pass=replace(pass,"!","") pass=replace(pass,"@","") pass=replace(pass,"#","") pass=replace(pass,"$","") pass=replace(pass,"%","") pass=replace(pass,"^","") pass=replace(pass,"&","") pass=replace(pass,"*","") pass=replace(pass,"(","") pass=replace(pass,")","") pass=replace(pass,"=","") pass=replace(pass,"\","") pass=replace(pass,"/","") pass=replace(pass,"|","") get_pass=pass
end function %>
'//
把send.asp和index.htm放到你的ASP目录下,然后再建一个news文件夹。打开浏览器,在地址栏里输入:http://你的机器名/你的ASP虚拟目录名/index.html输入文字,然后提交,OK!看看你的ASP目录里新建的news文件夹里是不是多了个新的文件夹,而且是以当前日期命名的。里面有你刚刚提交的文字,看看是不是生成了HTML文件。怎么样,你可以在此基础上做个简单的新闻发布系统。。 |
|
ASP 模板技术之参数传递
|
在内容系统开发中,涉及内容和形式分离的过程,也就是根据用户自定义页面模板然后替换成相关内容的过程。这和外面很多整站的内容管理系统,有本质上的区别。有不少内容管理系统,多少人用,都是一个样子,因为页面无法自定义,不懂编程的用户无法修改。象那种,只填几个参数就出来的网站,我估计是没有什么前途的。因为人人都是一个样子,人人都是会填那些参数的。
举个例子,你查看一下以下几个站点,你会认为他们是一套程序吗? www.blueidea.com http://pages.blueidea.com http://digi.blueidea.com http://wuyi.digichina.net http://www.dcshooter.com
如果我告诉你,他们都是一个程序,只是由相关的站长,设计不同的模板得到的页面显示,你就会发现,这个系统的优良性。
当然由于这套系统的高端性,目前普通用户无法使用,于是我开发了我自己的内容管理系统 kiss 内容管理系统。大家可以访问 http://aston.blueidea.com
而要给用户一个模板系统,首先,就是要有一个简单易懂的标记系统。大家看看下面的代码,看是否容易理解: <tag:loop channelid="1" pagesize="10" title="20" type="NEW" column="1">
略有HTML经验的人,就知道,这是一个模板标记里的循环标记,因为这是最常用的,你看我们网站的首页,列出10条文档也就只需要写一个这样的标记就完成了,这是不是让不明白编程的人,也很容易做出自己设计的页面出来呢?
参数说明: channelid 为一个栏目的在数据库中的ID pagesize 为列举多少个文档 title 为标题的长度 type 为列表列型,这里的”NEW”我们设定为最新的文档 column 为显示几列
以上介绍是给不会编程,或者对不了解内容系统的人做个普及,并且给我的内容管理系统打个广告,而且我想说的是,蓝色理想站点用的内容管理系统模板模块,要比我的强大很多。
下面轮到程序员了,其它人可以不用往下看。 那么怎么把它们的值读出来呢? 下面这个函数是最后的,用来解析所有模板的内容
代码拷贝框 '【功能】自定义模板标签
Function ProcessCustomTags(ByVal sContent)
Dim objRegEx, Match, Matches
'建立正则表达式
Set objRegEx = New RegExp
'查找内容
objRegEx.Pattern = "<tag:.*/>"
'忽略大小写
objRegEx.IgnoreCase = True
'全局查找
objRegEx.Global = True
'Run the search against the content string we've been passed
Set Matches = objRegEx.Execute(sContent)
'循环已发现的匹配
For Each Match in Matches
'Replace each match with the appropriate HTML from our ParseTag function
sContent = Replace(sContent, Match.Value, ParseTag(Match.Value))
Next
'消毁对象
set Matches = nothing
set objRegEx = nothing
'返回值
ProcessCustomTags = sContent
End Function
[Ctrl+A 全部选择 然后拷贝]
在上面的代码中,用到了正则表达式,如果你对它还不是很了解,请参阅相关资料,这里就不详细介绍了。
那么怎么取出参数值呢,也是一个函数: 代码拷贝框 '【功能】取得模板标签的参数名
'如:<tag:loop channelid="1" pagesize="10" title="20" type="NEW" column="1">
function GetAttribute(ByVal strAttribute, ByVal strTag)
Dim objRegEx, Matches
'建立正则表达式
Set objRegEx = New RegExp
'查找内容 (the attribute name followed by double quotes etc)
objRegEx.Pattern = lCase(strAttribute) & "=""[0-9a-zA-Z]*"""
'忽略大小写
objRegEx.IgnoreCase = True
'全局查找
objRegEx.Global = True
'执行搜索
Set Matches = objRegEx.Execute(strTag)
'如有匹配的则返回值, 不然返回空值
if Matches.Count > 0 then
GetAttribute = Split(Matches(0).Value,"""")(1)
else
GetAttribute = ""
end if
'消毁对象
set Matches = nothing
set objRegEx = nothing
end function [Ctrl+A 全部选择 然后拷贝]
OK好了,那怎么解析像上面<tagloop:>内容呢? 下面就是一个函数:
代码拷贝框 '【功能】解析并替换相应的模板标签内容
function ParseTag(ByVal strTag)
dim arrResult, ClassName, arrAttributes, sTemp, i, objClass
'如果标签是空的则退出函数
if len(strTag) = 0 then exit function
'Split the match on the colon character (:)
arrResult = Split(strTag, ":")
'Split the second item of the resulting array on the space character, to
'retrieve the name of the class
ClassName = Split(arrResult(1), " ")(0)
'Use a select case statement to work out which class we're dealing with
'and therefore which properties to populate etc
select case uCase(ClassName)
'It's a loop class, so instantiate one and get it's properties
case "LOOP"
set objClass = new LOOP_Class
LOOP.Channelid= GetAttribute("channelid", strTag")
LOOP.Pagesize= GetAttribute("pagesize", strTag")
LOOP.title = GetAttribute("title", strTag")
LOOP.type = GetAttribute("Type", strTag")
ParseTag = LOOP.column (GetAttribute("column", strTag"), true)
'Destroy our class object
set objClass = nothing
end select
end function [Ctrl+A 全部选择 然后拷贝]
上面的loop是一个类,这里也不再详说了。因为好久没有说话了,不太习惯,呵呵。 结论,通过上面的函数,你可以很快的编写相关的模板程序了。希望对你有帮助。 |
|
超长字符的智能分页-支持HTML
|
对HTML做了相应的处理,不会由HTML代码中切开。
这里另一位兄弟曾发表过一个,原理一样,不过我没仔细看过,不知有啥不同。
代码如下: -------------------------------------- 'Request Form Item I_Forder = Request.Form ("I_Folder") I_Topic = Request.Form ("I_Topic") I_Title = htmlencode(Request.Form ("I_Title")) I_Body = Request.Form ("body") I_Source = Request.Form ("I_Source") I_Keyword= htmlencode(Request.Form ("I_Keyword")) I_ISHOT = request.form("ishot") if i_ishot = "" then i_ishot="N" i_ispic = request.form("ispic") if i_ispic = "" then i_ispic ="N" i_pic = request.form("InsertImage") i_body = replace(i_body,"contentEditable=true","contentEditable=false")
'Check Input '......
'Get Pages ,B = Body B_Len = Len(I_Body) B_Pages = 1 'T = Temp T_Loop = true
Do While T_Loop '这里loop多次,每4000分一页,算出页码并加入库。 If B_Len > 4000 then N_Body = Left(I_Body,4000) 'N = New 'If "<P" in N_Body,Else ">" in N_Body If Instrrev(N_Body,"<P") > 0 and (Len(N_Body) - Instrrev(N_Body,"<P"))< 400 then N_Body = Left(N_Body,InstrRev(N_Body,"<P")-1) else if Instrrev(N_Body," ") > 0 and (Len(N_Body) - Instrrev(N_Body," "))< 400 then N_Body = Left(N_Body,InstrRev(N_Body," ")-1) Else If Instrrev(N_Body,"。") > 0 and (Len(N_Body) - Instrrev(N_Body,"。"))< 400 then N_Body = Left(N_Body,InstrRev(N_Body,"。")) Else If Instrrev(N_Body,";") > 0 and (Len(N_Body) - Instrrev(N_Body,";"))< 400 then N_Body = Left(N_Body,InstrRev(N_Body,";")) else if Instrrev(N_Body,",") > 0 and (Len(N_Body) - Instrrev(N_Body,","))< 400 then N_Body = Left(N_Body,InstrRev(N_Body,",")) else if Instrrev(N_Body,".") > 0 and (Len(N_Body) - Instrrev(N_Body,"."))< 400 then N_Body = Left(N_Body,InstrRev(N_Body,".")) end if end if End If End If end if End if
N_Len = Len(N_Body) I_Body = Mid(I_Body,N_Len+1) B_Len = Len(I_Body)
Else N_Body = I_Body T_Loop = false End If
'Add to database Exec_prc_Content_Ins I_Forder,I_Topic,I_Title,I_Source,N_Body,i_ispic,i_pic,i_ishot,I_Keyword,B_Pages
'这里一个function,你可以自己处理,反正结果有两个,一个是body,一个是b_pages,就是页码。
B_Pages = B_Pages + 1
Loop
%>
<html>
<head> <meta name="GENERATOR" content="Microsoft FrontPage 5.0"> <meta name="ProgId" content="FrontPage.Editor.Document"> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>新建网页 1</title> <link rel="stylesheet" type="text/css" href="../CSS/default.css"> </head>
<body>
<div align="center"> <center>
<table border=1 width="300" height="128" bordercolor="#000000" cellspacing="0" cellpadding="0" style="border-collapse: collapse"><tr> <td bgcolor="#DEDBD6" height="31"> 录入成功</td></tr><tr><td height="96"> <p align="center">此文章共分<%=B_Pages-1%>页 </td></tr></table>
</center> </div> <script> top.main_top.location.reload(); </script>
</body> |
|
将HTML表单数据存储为XML格式
|
通常的,ASP中表单提交的数据一般被写入数据库。然而,如果你想让发送数据更为简便易行,那么,可以将它书写为XML文件格式。这种方式对于在web上收集的数据更为有用。因为XML对于所用平台来说非常的简便,所以用不着转换数据格式。 将提交的数据写为XML文档,则需要通过Microsoft XMLDOM Object创建一个新的XML文档。Microsoft XMLDOM Object拥有一个可扩展对象库,通过它可以创建elements,attributes以及values,通过创建的这些项目则可以组成XML文档。我无法将整个目标模型做个完整的介绍,因为它所包含的内容太广泛,对于将建成的网站来说,目标模型甚至通过自身也能组建一个相对完整的部份。 在XMLDOM Object被创建出来之后,通过创建目标(此目标是关于组成XML文档中每一层的ELEMENTS而言)XML的结构会被演示出来。接下来,会举例说明XMLDOM是怎样被创建出来的。创建root element之后,将它附加在XMLDOM文件上。然后创建child elements并附加在root element上,最后存储文档。 演示Microsoft XMLDOM 对象 <% Dim objDom Dim objRoot Dim objChild1 Dim objChild2 Dim objPI " XMLDOM 对象使用Server对象的CreateObject方法创建 Set objDom = Server.CreateObject("Microsoft.XMLDOM") "使用XMLDOM的createElemnet方法创建一个IXMLDOMElement对象。 "createElemnet方法又一个string参数,这个string 表示该element的名称。 返回值被传递到objRoot变量。objRoot表示XML文档的根元素.。 Set objRoot = objDom.createElement("rootElement") "Use the appendChild Method of the XMLDOM Object to add the objRoot "Element Reference to the XML Document. objDom.appendChild objRoot "Now, following the same steps, you will create references to the "child elements for the XML Document. The only difference is, when the "child elements are appended to the document, you will call the "appendChild Method of the IXMLDOMElement Object rather than the "appendChild Method of the XMLDOM Object. By using the IXMLDOMElement "to append the chi en, you are differentiating (and applying tiered "structure to) the child elements from the root element. Set objChild1 = objDom.createElement("childElement1") objRoot.appendChild objChild1 Set objChild1 = objDom.createElement("childElement2") objRoot.appendChild objChild2 "The final step to take care of before saving this document is to add "an XML processing instruction. This is necessary so that XML parsers "will recognize this document as an XML document. Set objPI = objDom.createProcessingInstruction("xml","vertsion="1.0"") "Call the insertBefore Method of the XMLDOM Object in order to insert "the processing instruction before the root element (the zero element "in the XMLDOM childNodes Collection). objDom.insertBefore objPI, objDom.childNodes(0) "Calling the Save Method of the XMLDOM Object will save this XML "document to your disk drive. In this case, the document will be saved "to the "c:" drive and will be named "MyXMLDoc.xml". When saving an "XML document, if the file does not exist, it will be created. If it "does exist, it will be overwritten. objDom.Save "c:\MyXMLDoc.xml" %>
文档被存档之后,如果你再打开这个文档,那么则会以如下代码列表形式出现: MyXMLDoc.xml: <?xml version="1.0"?> <rootElement> <childElement1 /> <childElement2 /> </rootElement> 在"MyXMLDoc.xml"文档中,childElement1 和 childElement2 会以空的elements形式出现。如果它们被赋值,那么每个值都将由标记符括起来。 现在,让我们来思考一下如何将HTML数据写到XML文档中去。我们已经知道该如何创建和存储XML文档。将一个表单数据写到XML文档中去的过程,现在已演变成为Request Object"s Form Collection以及将每一个表单域的value书定到XML element value 中去的步骤重复。以上可以通过ASP来完成。 例:将数据输送到XML 现在,我们举一个普通的HTML表单的例子来说明。此Form有用户名,地址,电话,以及E-MAIL等几个域。并将这些信息写入XML文件中并保存。 EnterContact.html: <html> <head> <title> Contact Information </title> </head> <body> <form action="processForm.asp" method="post"> <h3>请输入你的联系方式</h3> First Name: <input type="text" id="firstName" name="firstName"><br> Last Name: <input type="text" id="lastName" name="lastName"><br> Address #1: <input type="text" id="address1" name="address1"><br> Address #2: <input type="text" id="address2" name="address2"><br> Phone Number: <input type="text" id="phone" name="phone"><br> E-Mail: <input type="text" id="email" name="email"><br> <input type="submit" id="btnSub" name="btnSub" value="Submit"><br> </form> </body> </html> 将Form 中数据发送到processForm.asp.。这是一个ASP页面,在这个ASP中将反复调用同一个函数将form数据写入XML文件。 processForm.asp: <% "-------------------------------------------------------------------- "The "ConvertFormtoXML" Function accepts to parameters. "strXMLFilePath - The physical path where the XML file will be saved. "strFileName - The name of the XML file that will be saved. "-------------------------------------------------------------------- Function ConvertFormtoXML(strXMLFilePath, strFileName) "Declare local variables. Dim objDom Dim objRoot Dim objField Dim objFieldValue Dim objattID Dim objattTabOrder Dim objPI Dim x "Instantiate the Microsoft XMLDOM. Set objDom = server.CreateObject("Microsoft.XMLDOM") objDom.preserveWhiteSpace = True "Create your root element and append it to the XML document. Set objRoot = objDom.createElement("contact") objDom.appendChild objRoot "Iterate through the Form Collection of the Request Object. For x = 1 To Request.Form.Count "Check to see if "btn" is in the name of the form element. "If it is, then it is a button and we do not want to add it "to the XML document. If instr(1,Request.Form.Key(x),"btn") = 0 Then "Create an element, "field". Set objField = objDom.createElement("field") "Create an attribute, "id". Set objattID = objDom.createAttribute("id") "Set the value of the id attribute equal the the name of "the current form field. objattID.Text = Request.Form.Key(x) "The setAttributeNode method will append the id attribute "to the field element. objField.setAttributeNode objattID "Create another attribute, "taborder". This just orders the "elements. Set objattTabOrder = objDom.createAttribute("taborder") "Set the value of the taborder attribute. objattTabOrder.Text = x "Append the taborder attribute to the field element. objField.setAttributeNode objattTabOrder "Create a new element, "field_value". Set objFieldValue = objDom.createElement("field_value") "Set the value of the field_value element equal to "the value of the current field in the Form Collection. objFieldValue.Text = Request.Form(x) "Append the field element as a child of the root element. objRoot.appendChild objField "Append the field_value element as a child of the field elemnt. objField.appendChild objFieldValue End If Next "Create the xml processing instruction. Set objPI = objDom.createProcessingInstruction("xml", "version="1.0"") "Append the processing instruction to the XML document. objDom.insertBefore objPI, objDom.childNodes(0) "Save the XML document. objDom.save strXMLFilePath & "\" & strFileName "Release all of your object references. Set objDom = Nothing Set objRoot = Nothing Set objField = Nothing Set objFieldValue = Nothing Set objattID = Nothing Set objattTabOrder = Nothing Set objPI = Nothing End Function "Do not break on an error. On Error Resume Next "Call the ConvertFormtoXML function, passing in the physical path to "save the file to and the name that you wish to use for the file. ConvertFormtoXML "c:","Contact.xml" "Test to see if an error occurred, if so, let the user know. "Otherwise, tell the user that the operation was successful. If err.number <> 0 then Response.write("Errors occurred while saving your form submission.") Else Response.write("Your form submission has been saved.") End If %>
如果你是在你自己的应用程序中使用以上代码,请谨记一件事情,在"ConvertFormtoXML"函数已经运行的情况下,如果XML文件名已经存在,那么,文件将会被覆盖。在此,我建议在使用"ConvertFormtoXML"功能前,最好用随机建立的文件名。这样,就将有价值数据被改写的风险降为零。 关于XML文件的产生,举例如下: Contact.xml <?xml version="1.0" ?> <contact> <field id="firstName" taborder="1"> <field_value>Michael</field_value> </field> <field id="lastName" taborder="2"> <field_value>Qualls</field_value> </field> <field id="address1" taborder="3"> <field_value>2129 NW 27th St.</field_value> </field> <field id="address2" taborder="4"> <field_value /> </field> <field id="phone" taborder="5"> <field_value>4055253988</field_value> </field> <field id="email" taborder="6"> <field_value>michaelq@vertiscope.com</field_value> </field> </contact> 我在此建议:将以上代码复制到你个人网站服务器上的同名页面上,并运行以上示例时。请一定要明确你使用的是对你个人服务器有效的路径和文件名。 当你一切准备好时,请再次检验你的XML文件。 |
|
XML操作类
|
<% Class XMLDOMDocument Private fNode,fANode Private fErrInfo,fFileName,fOpen Dim XmlDom ’返回节点的缩进字串 Private Property Get TabStr(byVal Node) TabStr="" If Node Is Nothing Then Exit Property If not Node.parentNode Is nothing Then TabStr=" "&TabStr(Node.parentNode) End Property ’返回一个子节点对象,ElementOBJ为父节点,ChildNodeObj要查找的节点,IsAttributeNode指出是否为属性对象 Public Property Get ChildNode(byVal ElementOBJ,byVal ChildNodeObj,byVal IsAttributeNode) Dim Element Set ChildNode=Nothing If IsNull(ChildNodeObj) Then If IsAttributeNode=false Then Set ChildNode=fNode Else Set ChildNode=fANode End If Exit Property ElseIf IsObject(ChildNodeObj) Then Set ChildNode=ChildNodeObj Exit Property End If Set Element=Nothing If LCase(TypeName(ChildNodeObj))="string" and Trim(ChildNodeObj)<>"" Then If IsNull(ElementOBJ) Then Set Element=fNode ElseIf LCase(TypeName(ElementOBJ))="string" Then If Trim(ElementOBJ)<>"" Then Set Element=XmlDom.selectSingleNode("//"&Trim(ElementOBJ)) If Lcase(Element.nodeTypeString)="attribute" Then Set Element=Element.selectSingleNode("..") End If ElseIf IsObject(ElementOBJ) Then Set Element=ElementOBJ End If If Element Is Nothing Then Set ChildNode=XmlDom.selectSingleNode("//"&Trim(ChildNodeObj)) ElseIf IsAttributeNode=true Then Set ChildNode=Element.selectSingleNode("./@"&Trim(ChildNodeObj)) Else Set ChildNode=Element.selectSingleNode("./"&Trim(ChildNodeObj)) End If End If End Property ’读取最后的错误信息 Public Property Get ErrInfo ErrInfo=fErrInfo End Property
’给xml内容 Public Property Get xmlText(byVal ElementOBJ) xmlText="" If fopen=false Then Exit Property Set ElementOBJ=ChildNode(XmlDom,ElementOBJ,false) If ElementOBJ Is Nothing Then Set ElementOBJ=XmlDom
xmlText=ElementOBJ.xml End Property ’================================================================= ’类初始化 Private Sub Class_Initialize() Set XmlDom=CreateObject("Microsoft.XMLDOM") XmlDom.preserveWhiteSpace=true Set fNode=Nothing Set fANode=Nothing
fErrInfo="" fFileName="" fopen=false End Sub
’类释放 Private Sub Class_Terminate() Set fNode=Nothing Set fANode=Nothing Set XmlDom=nothing fopen=false End Sub ’===================================================================== ’建立一个XML文件,RootElementName:根结点名。XSLURL:使用XSL样式地址 ’返回根结点 Function Create(byVal RootElementName,byVal XslUrl) Dim PINode,RootElement Set Create=Nothing If (XmlDom Is Nothing) Or (fopen=true) Then Exit Function If Trim(RootElementName)="" Then RootElementName="Root" Set PINode=XmlDom.CreateProcessingInstruction("xml", "version=""1.0"" encoding=""GB2312""") XmlDom.appendChild PINode Set PINode=XMLDOM.CreateProcessingInstruction("xml-stylesheet", "type=""text/xsl"" href="""&XslUrl&"""") XmlDom.appendChild PINode
Set RootElement=XmlDom.createElement(Trim(RootElementName)) XmlDom.appendChild RootElement Set Create=RootElement fopen=True set fNode=RootElement End Function ’开打一个已经存在的XML文件,返回打开状态 Function Open(byVal xmlSourceFile) Open=false xmlSourceFile=Trim(xmlSourceFile) If xmlSourceFile="" Then Exit Function
XmlDom.async = false XmlDom.load xmlSourceFile fFileName=xmlSourceFile
If not IsError Then Open=true fopen=true End If End Function ’关闭 Sub Close() Set fNode=Nothing Set fANode=Nothing
fErrInfo="" fFileName="" fopen=false End Sub ’读取一个NodeOBJ的节点Text的值 ’NodeOBJ可以是节点对象或节点名,为null就取当前默认fNode Function getNodeText(byVal NodeOBJ) getNodeText="" If fopen=false Then Exit Function Set NodeOBJ=ChildNode(null,NodeOBJ,false) If NodeOBJ Is Nothing Then Exit Function
If Lcase(NodeOBJ.nodeTypeString)="element" Then set fNode=NodeOBJ Else set fANode=NodeOBJ End If getNodeText=NodeOBJ.text End function ’插入在BefelementOBJ下面一个名为ElementName,Value为ElementText的子节点。 ’IsFirst:是否插在第一个位置;IsCDATA:说明节点的值是否属于CDATA类型 ’插入成功就返回新插入这个节点 ’BefelementOBJ可以是对象也可以是节点名,为null就取当前默认对象 Function InsertElement(byVal BefelementOBJ,byVal ElementName,byVal ElementText,byVal IsFirst,byVal IsCDATA) Dim Element,TextSection,SpaceStr Set InsertElement=Nothing If not fopen Then Exit Function
Set BefelementOBJ=ChildNode(XmlDom,BefelementOBJ,false) If BefelementOBJ Is Nothing Then Exit Function Set Element=XmlDom.CreateElement(Trim(ElementName)) ’SpaceStr=vbCrLf&TabStr(BefelementOBJ) ’Set STabStr=XmlDom.CreateTextNode(SpaceStr) ’If Len(SpaceStr)>2 Then SpaceStr=Left(SpaceStr,Len(SpaceStr)-2) ’Set ETabStr=XmlDom.CreateTextNode(SpaceStr) If IsFirst=true Then ’BefelementOBJ.InsertBefore ETabStr,BefelementOBJ.firstchild BefelementOBJ.InsertBefore Element,BefelementOBJ.firstchild ’BefelementOBJ.InsertBefore STabStr,BefelementOBJ.firstchild Else ’BefelementOBJ.appendChild STabStr BefelementOBJ.appendChild Element ’BefelementOBJ.appendChild ETabStr End If
If IsCDATA=true Then set TextSection=XmlDom.createCDATASection(ElementText) Element.appendChild TextSection ElseIf ElementText<>"" Then Element.Text=ElementText End If
Set InsertElement=Element Set fNode=Element End Function ’在ElementOBJ节点上插入或修改名为AttributeName,值为:AttributeText的属性 ’如果已经存在名为AttributeName的属性对象,就进行修改。 ’返回插入或修改属性的Node ’ElementOBJ可以是Element对象或名,为null就取当前默认对象 Function setAttributeNode(byVal ElementOBJ,byVal AttributeName,byVal AttributeText) Dim AttributeNode Set setAttributeNode=nothing
If not fopen Then Exit Function Set ElementOBJ=ChildNode(XmlDom,ElementOBJ,false) If ElementOBJ Is Nothing Then Exit Function Set AttributeNode=ElementOBJ.attributes.getNamedItem(AttributeName) If AttributeNode Is nothing Then Set AttributeNode=XmlDom.CreateAttribute(AttributeName) ElementOBJ.setAttributeNode AttributeNode End If AttributeNode.text=AttributeText set fNode=ElementOBJ set fANode=AttributeNode Set setAttributeNode=AttributeNode End Function ’修改ElementOBJ节点的Text值,并返回这个节点 ’ElementOBJ可以对象或对象名,为null就取当前默认对象 Function UpdateNodeText(byVal ElementOBJ,byVal NewElementText,byVal IsCDATA) Dim TextSection
set UpdateNodeText=nothing If not fopen Then Exit Function Set ElementOBJ=ChildNode(XmlDom,ElementOBJ,false) If ElementOBJ Is Nothing Then Exit Function
If IsCDATA=true Then set TextSection=XmlDom.createCDATASection(NewElementText) If ElementOBJ.firstchild Is Nothing Then ElementOBJ.appendChild TextSection ElseIf LCase(ElementOBJ.firstchild.nodeTypeString)="cdatasection" Then ElementOBJ.replaceChild TextSection,ElementOBJ.firstchild End If Else ElementOBJ.Text=NewElementText End If set fNode=ElementOBJ Set UpdateNodeText=ElementOBJ End Function ’返回符合testValue条件的第一个ElementNode,为null就取当前默认对象 Function getElementNode(byVal ElementName,byVal testValue) Dim Element,regEx,baseName Set getElementNode=nothing If not fopen Then Exit Function
testValue=Trim(testValue) Set regEx=New RegExp regEx.Pattern="^[A-Za-z]+" regEx.IgnoreCase=true If regEx.Test(testValue) Then testValue="/"&testValue Set regEx=nothing baseName=LCase(Right(ElementName,Len(ElementName)-InStrRev(ElementName,"/",-1)))
Set Element=XmlDom.SelectSingleNode("//"&ElementName&testValue)
If Element Is Nothing Then ’Response.write ElementName&testValue Set getElementNode=nothing Exit Function End If
Do While LCase(Element.baseName)<>baseName Set Element=Element.selectSingleNode("..") If Element Is Nothing Then Exit Do Loop If LCase(Element.baseName)<>baseName Then Set getElementNode=nothing Else Set getElementNode=Element If Lcase(Element.nodeTypeString)="element" Then Set fNode=Element Else Set fANode=Element End If End If End Function ’删除一个子节点 Function removeChild(byVal ElementOBJ) removeChild=false If not fopen Then Exit Function
Set ElementOBJ=ChildNode(null,ElementOBJ,false) If ElementOBJ Is Nothing Then Exit Function ’response.write ElementOBJ.baseName
If Lcase(ElementOBJ.nodeTypeString)="element" Then If ElementOBJ Is fNode Then set fNode=Nothing If ElementOBJ.parentNode Is Nothing Then XmlDom.removeChild(ElementOBJ) Else ElementOBJ.parentNode.removeChild(ElementOBJ) End If removeChild=True End If End Function ’清空一个节点所有子节点 Function ClearNode(byVal ElementOBJ) set ClearNode=Nothing If not fopen Then Exit Function Set ElementOBJ=ChildNode(null,ElementOBJ,false) If ElementOBJ Is Nothing Then Exit Function ElementOBJ.text="" ElementOBJ.removeChild(ElementOBJ.firstchild) Set ClearNode=ElementOBJ Set fNode=ElementOBJ End Function
’删除子节点的一个属性 Function removeAttributeNode(byVal ElementOBJ,byVal AttributeOBJ) removeAttributeNode=false If not fopen Then Exit Function Set ElementOBJ=ChildNode(XmlDom,ElementOBJ,false) If ElementOBJ Is Nothing Then Exit Function Set AttributeOBJ=ChildNode(ElementOBJ,AttributeOBJ,true) If not AttributeOBJ Is nothing Then ElementOBJ.removeAttributeNode(AttributeOBJ) removeAttributeNode=True End If End Function
’保存打开过的文件,只要保证FileName不为空就可以实现保存 Function Save() On Error Resume Next Save=false If (not fopen) or (fFileName="") Then Exit Function XmlDom.Save fFileName Save=(not IsError) If Err.number<>0 then Err.clear Save=false End If End Function
’另存为XML文件,只要保证FileName不为空就可以实现保存 Function SaveAs(SaveFileName) On Error Resume Next SaveAs=false If (not fopen) or SaveFileName="" Then Exit Function XmlDom.Save SaveFileName SaveAs=(not IsError) If Err.number<>0 then Err.clear SaveAs=false End If End Function
’检查并打印错误信息 Private Function IsError() If XmlDom.ParseError.errorcode<>0 Then fErrInfo="<h1>Error"&XmlDom.ParseError.errorcode&"</h1>" fErrInfo=fErrInfo&"<B>Reason :</B>"&XmlDom.ParseError.reason&"<br>" fErrInfo=fErrInfo&"<B>URL :</B>"&XmlDom.ParseError.url&"<br>" fErrInfo=fErrInfo&"<B>Line :</B>"&XmlDom.ParseError.line&"<br>" fErrInfo=fErrInfo&"<B>FilePos:</B>"&XmlDom.ParseError.filepos&"<br>" fErrInfo=fErrInfo&"<B>srcText:</B>"&XmlDom.ParseError.srcText&"<br>" IsError=True Else IsError=False End If End Function End Class %> |
|
用ASP+XML实现CSDN的菜单(数据库),可分权限管理
|
只有一个程序文件和一个数据库.文件很少,也很容易查错.但是功能完全实现了!
数据库结构:
Table:Menu ID parentid,int,4 MenuName,Char,20 Link,Char,50
Table:UserLevel ID UserID,int,4 MenuID,int,4
-------------------------------------程序源文件:MenuList.Asp------------------------------
<% '-------------------------------' '源创商务策划有限公司-OA系统 '模块名称:可权限控制的菜单 '-------------------------------'
set conn = Server.CreateObject("ADODB.Connection") conn.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+Server.mappath("tree.mdb")+";Persist Security Info=False") %>
<HTML> <HEAD> <TITLE> DSTree </TITLE> <style> body,td{font:12px verdana} #treeBox{background-color:#fffffa;} #treeBox .ec{margin:0 5 0 5;} #treeBox .hasItems{font-weight:bold;height:20px;padding:3 6 0 6;margin:2px;cursor:hand;color:#555555;border:1px solid #fffffa;} #treeBox .Items{height:20px;padding:3 6 0 6;margin:1px;cursor:hand;color:#555555;border:1px solid #fffffa;} </style>
<script> //code by star 20003-4-7 var HC = "color:#990000;border:1px solid #cccccc"; var SC = "background-color:#efefef;border:1px solid #cccccc;color:#000000;"; var IO = null; function initTree(){ var rootn = document.all.menuXML.documentElement; var sd = 0; document.onselectstart = function(){return false;} document.all.treeBox.appendChild(createTree(rootn,sd)); } function createTree(thisn,sd){ var nodeObj = document.createElement("span"); var upobj = document.createElement("span"); with(upobj){ style.marginLeft = sd*10; className = thisn.hasChildNodes()?"hasItems":"Items"; innerHTML = "<img src=expand.gif class=ec>" + thisn.getAttribute("text") +""; onmousedown = function(){ if(event.button != 1) return; if(this.getAttribute("cn")){ this.setAttribute("open",!this.getAttribute("open")); this.cn.style.display = this.getAttribute("open")?"inline":"none"; this.all.tags("img")[0].src = this.getAttribute("open")?"expand.gif":"contract.gif"; } if(IO){ IO.runtimeStyle.cssText = ""; IO.setAttribute("selected",false); } IO = this; this.setAttribute("selected",true); this.runtimeStyle.cssText = SC; } onmouseover = function(){ if(this.getAttribute("selected"))return; this.runtimeStyle.cssText = HC; } onmouseout = function(){ if(this.getAttribute("selected"))return; this.runtimeStyle.cssText = ""; } oncontextmenu = contextMenuHandle; onclick = clickHandle; }
if(thisn.getAttribute("treeId") != null){ upobj.setAttribute("treeId",thisn.getAttribute("treeId")); } if(thisn.getAttribute("href") != null){ upobj.setAttribute("href",thisn.getAttribute("href")); } if(thisn.getAttribute("target") != null){ upobj.setAttribute("target",thisn.getAttribute("target")); }
nodeObj.appendChild(upobj); nodeObj.insertAdjacentHTML("beforeEnd","<br>")
if(thisn.hasChildNodes()){ var i; var nodes = thisn.childNodes; var cn = document.createElement("span"); upobj.setAttribute("cn",cn); if(thisn.getAttribute("open") != null){ upobj.setAttribute("open",(thisn.getAttribute("open")=="true")); upobj.getAttribute("cn").style.display = upobj.getAttribute("open")?"inline":"none"; if( !upobj.getAttribute("open"))upobj.all.tags("img")[0].src ="contract.gif"; } for(i=0;i<nodes.length;cn.appendChild(createTree(nodes[i++],sd+1))); nodeObj.appendChild(cn); } else{ upobj.all.tags("img")[0].src ="endnode.gif"; } return nodeObj; } window.onload = initTree; </script>
<script> function clickHandle(){ if((this.getAttribute("href")!=null)&&(this.getAttribute("href")!="http://")) {parent.mainFrame.location.href=this.getAttribute("href");} //在MainFrame窗口打开连接。 }
function contextMenuHandle(){ event.returnValue = false; var treeId = this.getAttribute("treeId"); // your code here } </script> </HEAD> <BODY> <xml id=menuXML> <?xml version="1.0" encoding="GB2312"?> <DSTreeRoot text="系统菜单" open="true" treeId="123">
<%
Set rs = Conn.Execute("SELECT (select count(*) from Menu where Menu.parentid=x.id and Menu.ID in (SELECT UserLevel.menuid FROM UserLevel WHERE UserLevel.userid = 1)) AS children, * FROM Menu AS x WHERE x.id in (SELECT UserLevel.menuid FROM UserLevel WHERE UserLevel.userid = 1)") Do while not rs.eof if rs("ParentID")=0 then Count = Rs ("children") %> <DSTree text="<%=rs("Content")%>" href="<%=rs("Link")%>" open="false" treeId="<%=rs("ID")%>"> <% rs.MoveNext end if for i=1 to Count %> <DSTree text="<%=rs("Content")%>" href="<%=rs("Link")%>" open="false" treeId="<%=rs("ID")%>"> </DSTree> <% Rs.MoveNext Next Response.write("</DSTree>") Loop
rs.close Conn.close Set rs = Nothing Set Conn = Nothing %>
</DSTreeRoot> </xml> <table style="position:absolute;left:0;top:0;"> <tr><td id=treeBox style="width:400px;height:200px;border:1px solid #cccccc;padding:5 3 3 5;" valign=top></td></tr> </table> </BODY> </HTML> |
|
|