一般介绍动态网页开发的资料都会机械式地先讲HTML,再则有空讲讲JS,然后切入正题讲动态网页部分,最后给出一些实例,比如留言板、论坛,甚至小型电子商务网站等等。而更新的ASP.Net甚至可能只从WinForm讲起,然后就讲WebForm了……这样更加使程序员无法接触底层的代码,无法理解整体架构和工作流程。我认为ASP.Net的出现有点像高级语言的诞生,高级语言的编译器实现了自动编译链接高级语言代码到汇编代码的过程,虽然最终的代码未必那么简洁,但毕竟经多重优化也在可接受范围内。而如今的ASP.Net原意想封装所有的客户端代码,实现从WebUI+CodeBehide到HTML的自动生成过程,但由于种种原因现在还做不到完全满足开发者需要(可以这么说,它产生的“汇编代码”不尽如人意),很多基本功能需要了解客户端脚本,进行手工修改才能实现。
正是ASP.Net现在所处的这种矛盾阶段,我们更有理由要掌握更多的知识,从HTML、CSS到JScript、behavior、XML。言归正传,本文将直接把服务器端脚本和客户端脚本放在一块讲述比较,这是极少有人做过的,也可以解开一些入门者的困惑,比如为什么服务器端脚本就是不能弹出一个对话框、弹出确定框、打开新窗口等等问题。再看看这二者到底管辖和作用了怎样的范围,然后再举例来认识一下如何使这两个脚本间可以交互,以实现更强的功能。
图为早期PHP4的分层示意,虽然从现在的n层架构来看画得不甚清楚,但还是能看懂的。两个脚本很简单:顾名思义,一个运行在服务器端,一个运行在客户端。而它们的任务也很明确:服务器端脚本只用于生成网页代码(可以包括HTML、CSS、JS等等),它正是平常所说的ASP/ASP.Net、PHP、JSP等等,在动态网页中一般用“<%%>”、“<??>”等符号包围,在多层构架中也可以把Beans,CodeBehide等等算进去吧。客户端脚本就完全是在客户浏览器里解释运行的,要么在“<script>”中,要么在一些事件里,要么单独一个文件,总之查看源代码一般都可以看到,对最终浏览用户相对是公开的。它控制着用户与浏览器的交互,如果把浏览器看成应用程序,它的所有动作都是客户端脚本完成的,这就解释了为什么总是没有弹出对话框的服务器端函数。
因为ASP本身用的脚本与客户端脚本完全一样,都是JScript(或JavaScript)和VBScript,所以经常让初学者感到摸不着头脑,还有很容易使人混淆的<script runat="Server">这个标志。其实还是上面说的原则,用“<%%>”包围起来的代码肯定是服务器端脚本,当然还有<script runat="Server">里的(这不都标明了是运行在服务器端的嘛),这些代码经过Web服务器解释运行后在最后的HTML代码中肯定是找不到的。还有一点要明白的是,无论是JS还是VBS都可以用来写任何一端的脚本,只是一般比较习惯用JS来写客户端脚本罢了。至于一般用VBS来写服务器端脚本可能一个是习惯,一个是以示区别。
ASP.Net用RegisterClientScriptBlock()、RegisterStartupScript()等方法来在代码中添加客户端脚本,以及control.Attributes["event"]="script"来为控件添加事件处理脚本。懂得这些和一点JScript知识你也许知道如何实现在按个删除按钮之前弹出一个确认窗口了,把下面代码写在Page_Load里:
btnDel.Attributes["onClick"]="return confirm('确定要删除吗?');";
但如果你多懂得一点内幕,马上就会发现这样虽然能行,但是有很致命的副作用:如果同一页面中设有validator,尽管validator可以报告有错误的输入,但它们都不能阻止表单提交了!原因在于ASP.Net把你自己写的那段JScript代码写在了按钮onclick的最前面:
<input type="submit" name="btnDel" value="Button" onclick="return confirm('确定要删除吗?');if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnDel" style="……" />
这样原来的if语句后的那条就无法执行了,而Page_ClientValidate()正是ASP.Net自带的WebUIValidation.js里的函数,而一旦影响该函数的正常运行则会使表单不能按原定的方式判断提交。奇怪的是MS自身提供的范例也有这么做的。我们稍微更改一下onClick的脚本来获得正确的做法:
btnDel.Attributes["onClick"]="if confirm('确定要删除吗?') return false;"; 可见客户端脚本的使用是无处不在的,有时需要熟练的技巧和敏锐的决策,在过去的ASP时代如此,现在的.Net时代亦不外如是。
# re: 分清脚本——网页中的服务器端和客户端脚本(二)2005-01-24 20:19 | 奇思软件
或许用我写的一个组件更方便:)
此组件从标准button继承,但在提交之前显示提示框,依旧支持验证
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace Keyss.WebControls
{
[ToolboxData("<{0}:Button runat=server></{0}:Button>")]
public class Button : System.Web.UI.WebControls.Button
{
protected static string _warningScript = "if(!window.confirm('{0}')) return false;";
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public string WarningMessage
{
get
{
object o = ViewState["_warningMessage"];
return o==null?string.Empty:o.ToString();
}
set
{
ViewState["_warningMessage"] = value;
}
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(false)
]
public bool EnableWarning
{
get
{
object o = ViewState["_enableWarning"];
return o==null?false:(bool)o;
}
set
{
ViewState["_enableWarning"] = value;
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit (e);
if(this.EnableWarning)
{
string onClick = this.Attributes["onclick"];
if(onClick == null)
{
this.Attributes["onclick"] = string.Format(_warningScript,this.WarningMessage);
}
else
{
this.Attributes["onclick"] = string.Format(_warningScript,this.WarningMessage) + onClick;
}
}
}
}
}