引言:
最近看北大青鸟视频的时候有一集里面提到了关于网页中服务器端和客户端脚本的区别,所以特地查了查,觉得这个博客写的蛮好的,于是重新整理了一遍。
ASP.Net的反思——网页中的服务器端和客户端脚本(一)
步入.Net时代,MS想让人们把网页开发当成应用程序一样开发,而且还在ASP.Net 2.0加了很多控件,像Loginform,Treeview等等。但在网页脚本语言(如ASP、PHP、Perl等)和J2EE还在继续占领着WWW大部分江山的情况下,如果只懂得写codebehide里的东东是远远不够的。
现在很多ASP.Net初学者居然都不知道何为JavaScript,或者只是听说过,而不甚了解。比如很多新手问这样的问题:
如何用ASP/ASP.Net弹出一个对话框?
尽管这对一个网页老手来说是轻而易举、嗤之以鼻的小事,甚至他们会大惑不解,连这都不懂还来编网页?
这正是应用程序和网页的最大区别,网页是由HTML、CSS、客户端脚本、行为等等各种元素组成的复杂产物,因为不能与Web服务器保持实时连接,所以很多东西不能由服务器端来控制。
我期待着MS将如何填补这道沟壑,希望在VS.Net2005正式版中能看到一些改变(一直在想MS是否有可能把弹出对话框做成一个控件或包装成Web.MessageBox类,呵呵)。VS.Net 2003中根本没看到对方便编写客户端脚本的支持,这又是出于怎样的考虑?
还有一个问题也是值得斟酌的:ASP.Net的提出应该是针对企业级用户的多层架构需求,而现在盲目地把它用于开发普通的网站,VS.Net默认产生的大量垃圾网页代码对于现在平均带宽以K计的中国(CNNIC2005年最新的统计报告表明拨号和ISDN占44.5%的用户数量,)是否过于累赘呢?
不再强调使用CSS文件;不再强调使用SSI(Server Side Include);自动产生的一堆加密JS控制脚本;一旦编写不当动辄提交整个网页来获取少量的数据:这些无论对服务器还是客户都加重了负担……看来ASP.Net更需要知识全面缜密的程序员!
分清脚本——网页中的服务器端和客户端脚本(二)
一般介绍动态网页开发的资料都会机械式地先讲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里:
<span style="font-family:KaiTi_GB2312;"><span style="font-family:FangSong_GB2312;font-size:18px;">btnDel.Attributes["onClick"]="return confirm('确定要删除吗?');";</span></span>
但如果你多懂得一点内幕,马上就会发现这样虽然能行,但是有很致命的副作用:如果同一页面中设有validator,尽管validator可以报告有错误的输入,但它们都不能阻止表单提交了!原因在于ASP.Net把你自己写的那段JScript代码写在了按钮onclick的最前面:
<span style="font-family:KaiTi_GB2312;"><span style="font-family:FangSong_GB2312;font-size:18px;"><input type="submit" name="btnDel" value="Button" onclick="return confirm('确定要删除吗?');if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnDel" style="……" /></span></span>
这样原来的if语句后的那条就无法执行了,而Page_ClientValidate()正是ASP.Net自带WebUIValidation.js里的函数,而一旦影响该函数的正常运行则会使表单不能按原定的方式判断提交。奇怪的是MS自身提供的范例也有这么做的。我们稍微更改一下onClick的脚本来获得正确的做法:
<span style="font-family:KaiTi_GB2312;">btnDel.Attributes["onClick"]="if(!confirm('确定要删除吗?')) return false;";</span>
可见客户端脚本的使用是无处不在的,有时需要熟练的技巧和敏锐的决策,在过去的ASP时代如此,现在的.Net时代亦不外如是。
善用脚本交互——网页中的服务器端和客户端脚本(三)
懂客户端脚本的未必是好的Web程序员,但只懂服务器端脚本或编程的肯定不会是好的Web程序员。至少在现今阶段,要写出高效Web网页或Web应用程序,不对这两个脚本充分理解熟谙于心是不行的。聪明的程序员能灵活使用脚本,对各种Web程序的业务流程得心应手。
比较常用的技巧是用服务器端脚本来写客户端脚本,这里用一个较流行的局部刷新的例子来展示该技巧。前提是对客户端脚本有较好的了解。
“<script>”标签有个属性src,其值可以设置为一个js文件,文件中即是客户端脚本。因为没规定该js文件是静态文件,而且可以用脚本来更改src指向的文件,所以可以巧妙地使用这个特性来实现动态局部刷新(当然,frame、iframe等也有src属性,均可考虑,这里用script方便一点)。这里有两个网页,一个test1.htm是主页面,而另一个test.asp其实是js文件,只不过它的内容是动态的。
test1.htm
<input name="txt" type="text" size="10" maxlength="10" /> <script id="s" src="test.asp"></script> </script> function func(){ s.src="test.asp"; txt.value=sTxt; } setInterval("func()",1000); </script>
test.asp
//JScript <% response.cachecontrol="no-cache" ' 不使用缓存,确保页面更新 sTxt=… ' 动态地获得一个值 %> sTxt="<%=sTxt%>"; //注意这里两个sTxt,前一个是客户端,后一个是服务器端变量
这样在主页面test1.htm中每隔1秒就会看到文本框“刷新”一次,实现了局部刷新。把该技术加以扩展推广可以满足更复杂的需求。注意理解test.asp中的两个sTxt变量及两种注释方法,记住ASP是写在<%%>中的,是用VBScript写的,所以注释用单引号“'”;客户端脚本用JScript写的,所以注释用两个斜杠“//”。
这是服务器端脚本把变量传给客户端脚本的例子,如果还不明白就动手做做实验,在浏览器中输入test.asp地址看它到底输出了什么。至于客户端脚本把变量传给服务器端的例子就司空见惯,平常用得再多也不过了,如表单数据提交之前的简单处理再交给服务器就是一例,这里就不具体阐述了。所以也许在不知不觉中我们就在做着二个脚本之间的交互工作。
最近又看到有人用JS在客户端创建XMLHTTP组件来读网页来实现局部刷新,当然这种技术是无法跨平台的;还有Web Service、Remoting等技术来实现局部刷新,都是不错的主意,自从MS的JScript可以创建ActiveX对象,逐渐支持面向对象特性后,客户端脚本威力愈发强大。对我们来说,一旦分清楚服务器端和客户端脚本的辖区及作用,下功夫看些网页客户端脚本语言知识,善用脚本交互,就不难理清Web程序的思路,打开层层迷障,完成各种任务!