posts - 8, comments - 15, trackbacks - 0, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

2008年4月29日

上次写了一篇《web开发过程中要注意的问题》,得到了网友的大力支持,许多著名网站,也进行了转载,许多网友纷纷发来email,希望我能够贡献更多的经验给大家,于是时隔数月,决定写《web开发过程中要注意的问题(二)》,希望其中的经验和总结能够对您所有帮助。

1,不要认为Struts已经过时了,也不要盲目的去追随JSF以及更新的MVC框架,在目前Struts仍旧是最为优秀的MVC框架,尤其是后来与Spring、Hibernate(或者Ibatis)的结合,使得Struts的应用得到了进一步的发展,也许你认为Webwork2、SpringMVC或者JSF更为优秀和实用,那么也没有关系,其实只要对你或你的公司适用,那么就可以了。

2,你知道Javascript中的typeof和instanceof操作吗,如果不知道,劝你还是看看这方面的知识吧,typeof返回的是对象的类型,例如string、number、object等等,而instanceof判断的是一个对象是否是某个类的实例,例如:
  var arr=new Array();
  var type=typeof(arr);//返回object
  var flag=arr instanceof Array;//返回true
  var flag2=arr instanceof Object;//返回true;
  在实际使用过程中,你会发现instanceof是更为强大的,当然了许多时候typeof用起来很方便,但是对于复杂的场合typeof就不太适用了,尤其是对于自定义对象以及对象之间有着复杂的继承关系时,使用instanceof可以方便的对这些进行判断。

3,虽然你可能知道javascript中typeof的用法,但是如果你不能做对下面的题,说明你对typeof的理解还是不够的,例如:
  var a;
  var rs=typeof(a);//请问rs的值是什么?
  (A)object (B)variable (C)undefined (D) string (E)null (F)以上答案全不正确
  如果你选择A还算对JS有一些了解,如果选择B则基本上是乱猜的,如果选择D什么也说明不了,如果选择E则说明你对于Java和Javascript有些东西还没有分清楚,选择F也是不正确的。答案是C,记住在Javascript之中,如果一个变量没有初始化,那么该变量的类型为undefined。

4,也许你一直在抱怨Javascript之中没有列表、哈西表以及堆栈、队列等数据结构,如果真的在抱怨,那么也不是你的错,毕竟包括我自己在内,我们对JS的了解太少了,其实在JS之中,数组对象自身完全支持上面的那些数据结构,例如:
  var list=new Array();//列表
  list[0]="a";
  list[100]="b";
  var map=new Array();//哈西表
  map["001"]="a";
  map["username"]="zhangsan";
  var stack=new Array();//堆栈,即后进先出
  stack.push("a");
  stack.pop();
  var queue=new Array();//队列,即先进先出
  queue.unshift("a");
  queue.shift();
  可见JS是非常强大的,关键是我们知道的太少了,关于Javascript对于数组的操作,你也可以参考《Javascript对数组的操作》。

5,作为一个web开发人员,我们不能指望美工在完成漂亮的效果图之后,还要为我们将图切分,最后生成html文件后再给我们,然后我们对这些html文件,再修改转换为jsp、asp或者php文件。我一直认为效果图的切分应该或者最好由我们程序员自己来做,因为美工做的效果图实际上是要应用到我们的产品或者项目中的,而具体的产品和项目,对效果图中哪些部分是需要输入文字的,哪些地方是需要背景的,哪些地方是需要可以自动伸缩的,而哪些地方又是必须保证大小的,是有很严格的要求的,尤其是我们的产品或项目中如果使用了类似sitemesh等的模板技术,那么切图的工作就更要由我们自己来做了。这样并不是说美工不需要懂得html、css等技术,也不是说美工切出的图,会不符合我们的要求,我们知道,一张效果图,可以有n种切法,但是要能够满足实际的需求,往往只有一种最合适的切法,而这个切法一般来说美工是不太清楚的,开发人员也是不清楚的,只有既是开发人员,又懂得美工切图的人,才能够找到最为合适的切分方法,而这样的人才是非常奇缺的!

6,不要过于痴迷Ajax技术,也不要过于追捧web2.0这个时髦的词汇,并不是说什么东西粘上ajax或者web2.0,就能够火起来或者对我们的实际发展有利的,如果你是做公网网站的,那么要注意,不合适的ajax使用,会使得网站被搜索引擎收录的信息大幅度减少,但是ajax或者Flex2等技术对于用户体验而言,还是相当不错的,因此是否使用ajax等技术,一要看对你们的解决方案宣传是否有作用,另外一点就是要看,它是否真正的改进了我们的应用。

7,对于ajax的post提交方式,可能你有些问题要问,例如post的方式是不是只要在open时指定method就可以了,为什么我将大数据放到url后面,而没有被完全传递过去,为什么我后台使用类似jsp中的request.getParamter方法接收不到数据,我们通过一个例子看一下ajax发送/接受大数据的方式:

  1)send.jsp:(我举的例子使用的是Javascript开源框架JsJava的ajax类库,该类库对IE和Firefox等的XMLHttpRequest等对象进行了易用性的封装,不像prototype.js默认对传递的数据进行urlencode编码)

 var ajaxRequest=new AjaxRequest();
 ajaxRequest.setRequestMethod("post");
 ajaxRequest.setRequestURL("ajaxresponse.jsp");
 ajaxRequest.setAsync(true);
 ajaxRequest.setMethodOnSuccess(onSuccess,[ajaxRequest]);
 ajaxRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");
 ajaxRequest.send("content=这是一篇几千字的文档...在此省略");

  要注意设置发送方式为post,设置头信息的内容类型为application/x-www-form-urlencoded,charset是否设置要看内容的编码情况,另外大数据就放到send之中,记住大数据不是放在url的参数之中的。

  2)receive.jsp

    InputStream stream=request.getInputStream();
    InputStreamReader isr=new InputStreamReader(stream);
    BufferedReader br=new BufferedReader(isr);
    String str=br.readLine();   
    System.out.println(str);
    br.close();

  要知道,对于ajax post方式提交的数据,在服务器端如果是jsp不是简单使用getParameter就能取得到的,需要从输入流中去取,这和附件上传有些类似的地方。当然要注意编码和解码的问题。

8,我们在界面中经常会通过setTimeout方法来实现定时或者异步操作,例如:
  setTimeout(myfunc,2000);//两秒后执行myfunc函数
  但是要注意setTimeout方法并不能阻止后面js代码逻辑的执行,例如:
  <script>
    var a =8;
    setTimeout(myfunc,3000);
    document.write("wait...");
  </script>
  上面的代码中,document.write("wait...");逻辑并不会等到3秒后才执行,而是立即执行的,其实这一点可能大部分开发人员都知道,但是如果不注意,就很容易犯下面的错误,如下面代码所示:
  var ajax2HasExecuted=false;
  var ajaxRequest1;
  function ajax1Func(){
    if(!ajax2HasExecuted){
      setTimeout(ajax1Func,200);
   }
   var text=ajaxRequest1.getResponseText();
   ...
  }
  var ajaxRequest2;
  function ajax2Func(){
   var text=ajaxRequest2.getResponseText();
   ...
   ajax2HasExecuted=true;
  }
  上面的代码是一个页面中同时发送了两个ajax异步请求,分别有两个对应的接收操作,而业务逻辑要求,这两个操作是要有先后顺序的,其中第一个接收操作,需要等待第二个接收操作完成之后,才能进行处理,于是第一个操作中就采用setTimeout的方式,本意是在执行第一个操作的开始的地方,先判断第二个操作是否已经执行完毕,如果没有执行完毕,则等待200毫秒后,重新执行第二个操作,然后由于setTimeout并不能组织后续的逻辑继续执行,所以实际上不管第二个操作是否完成,第一个操作都会一直往下执行下去,从而导致业务上的错误。解决方法要么是在if后面加上else,或者在setTimeout之后直接return,例如:
  if(!ajax2HasExecuted){
      setTimeout(ajax1Func,200);
      return;
   }

9,window.open和window.showModalDialog方法相信你已经用到过许多次了,但是总是出现这样或那样的问题,问题主要是以下几个方面:
1)showModalDialog这个函数名经常被写错,例如经常被写成showModelDialog,使得不能执行打开窗口的操作。
2)控制打开窗口的属性,例如尺寸、滚动条、菜单、状态栏等,是我们经常会碰到的情况,但是我们经常会将这两种打开方式的属性名称以及属性之间的分隔符混用,使得属性执行不正确,例如我举下面的例子,要求弹出一个宽200高300的窗口,你看哪些方式是对的?
(A)  window.open("about:blank","","width=200,height=300");
(B)  window.open("about:blank","","width:200,height:300");
(C)  window.open("about:blank","","width=200;height=300");
(D)  window.open("about:blank","","width:200;height:300");
(E) window.showModalDialog("about:blank","","dialogWidth:200px;dialogHeight:300px");
(F) window.showModalDialog("about:blank","","dialogWidth=200px;dialogHeight=300px");
(G) window.showModalDialog("about:blank","","dialogWidth:200;dialogHeight:300");
再多的选项就不写了,正确答案是A和E,通过上面的问题我们需要记住一下几点:

  • window.open控制属性之间的分隔符是逗号“,”,属性和值之间用等于号"="连接
  • window.showModalDialog控制属性之间的分隔符是分号“;”,属性之间的用冒号“:”连接
  • window.open控制属性中长度和宽度尺寸可以直接写数字,也可以加上度量,例如px,但是对于window.showModalDialog的长度和宽度则必须带上px,否则尺寸无效,这一点是很重要的。

10,对于数据库中的varchar型字段,是有长度限制的,例如oracle10g中varchar2字段的最大长度为4000字符,在mysql中varchar最长为255字符,要注意这里面的限制值是单字节字符值,而汉字属于双字节字符,因此对于汉字存储而言,varchar2字段最多可以存储2000个汉字,由此引申出来的一个问题,就是web开发过程中的表单提交验证问题,因为对于中国用户而言,输入的内容有可能是汉字和英文字符的组合,因此判断输入字符串的长度需要注意,Javascript中判断一个字符串的长度的方法为:
  var str="abcdef";
  var length=str.length;
但是字符串的这个属性,计算的是独立字符的长度,例如一个中文字符按长度1计算,因此如下:
  var str="你好";
  var length=str.length;
其长度的值为2,而不是4,那么如何计算含有汉字或者说是双字节字符的真实长度呢?通过搜索可以很快找到方法,就是先将双子节字符替换为两个单字节字符,然后计算替换后的字符的长度,当然了JsJava中提供了对于双字节字符串真实长度的计算支持,你可以查看其中的StringUtils类。

11,如果你不能默写出常用颜色的英文表示值和16进制表示值,那么说明你的HTML基本功还是需要练的,例如白色是white,十六进制是FFFFFF,红色是red,十六进制是FF0000,蓝色是blue,十六进制是0000FF,紫色是purple,橙色是orange,网页中常用的灰色一般都是EEEEE,或者再浅一些EFEFEF,当然说这些并不是让你去背大量的颜色和十六进制值,但掌握一些常用的,还是很有必要的。

12,Javascript支持多维数组,但是没有构造函数可以直接生成多维数组,例如一维数组可以通过Array生成,例如:
  var arr=new Array(12);
生成多维数组,虽然没有构造函数支持,但是可以通过另外一种方式实现,例如实现一个12x5的二维数组:
  var arr=new Array(12);
  for(var i=0;i<arr.length;i++){
    arr[i]=new Array(5);
  }
另外,你可以直接使用JsJava的标准类MultiDimensionArrayUtils,支持生成二维和三维数组。

13,对于img标签,我们知道它有一个align属性,这个align是控制该图片与临近文本的位置关系,按照MSDN的说法,该属性的默认值是left,但是从实际的显示效果来看,好像并非如此,我们可以一起来比较一下不写align属性和将align赋值为left的情况,如果默认就是left,那么不写align和将align赋值left,其效果应该是一样的,那我们来一下:
<img src="http://jsjava.sourceforge.net/images/logo.gif">JsJava是最优秀的Javascript类库解决方案和界面应用开发支撑框架!
效果如下:

再看加入align=left的情况:
<img src=http://jsjava.sourceforge.net/images/logo.gif" _fcksavedurl="http://jsjava.sourceforge.net/images/logo.gif"" _fcksavedurl="http://jsjava.sourceforge.net/images/logo.gif"" _fcksavedurl="http://jsjava.sourceforge.net/images/logo.gif"" _fcksavedurl="http://jsjava.sourceforge.net/images/logo.gif"" align="left">JsJava是最优秀的Javascript类库解决方案和界面应用开发支撑框架!
效果图如下:

从实际效果来看,img的默认align并非是left,好像应该是bottom,而且上面的情况在IE6.0和Firefox2.0上都试验过,看来MSDN的说法是不太可信的,或者是自己理解错了?你可以看一下MSDN中的描述:http://msdn2.microsoft.com/en-us/library/ms533066.aspx

14,在界面中添加事件的方式主要有如下几种,例如当页面加载之后,执行函数myfunc,几种定义方式如下:
1)在<body/>标签中加入onload事件,即:
<body onload="myfunc()"...>
2)在任何一个可以执行Javascript的地方定义window.onload,即:
window.onload=myfunc;
3)在<script/>标签中定义,即:
<script for=window event=onload>
  myfunc();
</script>
4)将事件加入到事件队列中,即:
IE中 window.attachEvent("onload",myfunc)
Firefox中 window.addEventListener("load",myfunc,false)
建议大家使用第四种方式,因为只有第四种方式,可以避免将其它的同类事件覆盖,第四种方式是将该事件加入到同类的事件的队列之中,不会覆盖其它的同类事件,这在web开发过程种,是需要特别注意的,尤其我们自己定义一些界面框架或者组建的时候,经常需要定义onload事件,这个时候最好是使用第四种方式,因为引用界面框架和组建的用户,可能在页面上也想使用onload逻辑,当然用户自己使用第四种方式也不会有问题,但是做为一个负责任的界面高手,是不应该这样想得,我们应该严于律己,而宽以待人。

15,并不只是body(或者说window)有onload事件,<iframe/>中也可以定义onload事件,还有<img/>也可以定义onload事件,例如当图片加载完毕后,在window的状态栏种显示加载成功的字样:
<img src=http://jsjava.sourceforge.net/images/logo.gif" onload="window.status='加载完毕!'">
当然了对于img,你最好深入研究一下其各个事件和属性的用法,你会发现原来不知道的东西还有那么多,当然肯定有不少开发人员,已经对这一点有所研究了,但是大多数开发人员还是缺乏对这方面知识的了解。

16,如何在HTML种加入一段保留格式化的文本,相信你会想到<pre></pre>标签,例如:
<pre>
  这是一段格式化文本,
里面的文字直接将格式输出
</pre>
显示结果为:
  这是一段格式化文本,
里面的文字直接将格式输出

对于一般情况而言,pre标签就够用了,但是pre标签的不足之处,在于它不能将其中的html标签也原样输出,而是进行了解析,例如:
<pre>
  这是一段格式化文本,<font color="red">里面的文字</font>直接将<br>格式输出
</pre>
显示结果为:
  这是一段格式化文本,里面的文字直接将
格式输出

那么如何才能将含有HTML的内容也原样输出呢?实际上在HTML规范种有<xmp/>标签,可以实现这种效果,例如:
<xmp>
  这是一段格式化文本,<font color="red">里面的文字</font>直接将<br>格式输出
</xmp>
显示结果为:
  这是一段格式化文本,<font color="red">里面的文字</font>直接将<br>格式输出

17,如何获取某个对象区域的尺寸以及坐标,是我们界面开发过程种经常会遇到的一个问题,一般我们都采用getBoundingClientRect方法来获取对象的区域,进而得到该区域的尺寸和坐标,但是该方法只能在IE中使用,当然Firefox也有类似的方法,相信大多数开发人员不知道,该方法就是getBoxObjectFor,为了不想为跨浏览器而操心,你可以直接下载JsJava,使用其中的DocumentUtils类的getElementRectangle静态方法,例如:
<script src="jsjava.js"></script>
<script>
  var elemObj=document.getElementById("div1");//div1是一个div的id
  var rect=DocumentUtils.getElementRectangle(elemObj);//返回的rect是JsJava中的Rectangle对象
  var x=rect.getX();
  var y=rect.getY();
  var width=rect.getWidth();
  var height=rect.getHeight();
</script>
JsJava的类和方法都是经过IE和Firefox测试的,使用起来很方便。

18,在界面中对象的位置的计算与理解是比较麻烦的一件事情,例如clientHeight、clientTop、scrollHeight、scrollTop、offsetHeight、offsetTop,这些该怎么区分,又分别代表什么意思,对位置属性的深入理解,非常有助于对HTML界面布局本质的理解,是成为高手的必由之路,下面就简单介绍一下:
1)clientHeight,代表对象区域的屏幕高度,不包含区域的border尺寸,但包含padding的尺寸
2)clientTop,对象区域offsetHeight与clientHeight的差的一半
3)scrollHeight,代表对象区域内容的底部距区域最上边的距离
4)scrollTop,代表对象区域滚动部分的高度,即区域的最上边距离该区域可见部分的最上边的距离
5)offsetHeight,代表对象区域的屏幕高度,包含border和padding尺寸
6)offsetTop,代表对象区域距离上一个对象高度
上面的解释如果没有实际的经验,多少会有些迷糊,没有关系,我给你一个示意图:

因此,scrollHeight并非总是大于或等于clientHeight,实际上确实有一些开发人员认为一个区域没有滚动时scrollHeight和clientHeight相等,有滚动时scrollHeight=clientHeight+scrollTop,这种认识是不对的或者说是不准确的。
上面的图的html源码为:
<script>
  function pos(){
    debug(test1.clientHeight);
    debug(test1.clientTop);
    debug(test1.scrollHeight);
    debug(test1.scrollTop);
    debug(test1.offsetHeight);
    debug(test1.offsetTop);
    debug("--------------");
    debug(test2.clientHeight);
    debug(test2.clientTop);
    debug(test2.scrollHeight);
    debug(test2.scrollTop);
    debug(test2.offsetHeight);
    debug(test2.offsetTop);
    debug("--------------");
  }
  function debug(str){
    info.value+=str+"\n";
  }
</script>
<body onclick="pos()">
  <div id="test1" style="padding:5;border-width:15;border-color:black;border-

style:solid;background-color:red;height:100;width:200">区域1,高100</div>
  <span id="test2" style="background-color:blue;height:50;width:200">区域2,高50</span>
  <div id="test4" style="height:100;width:200;background-color:green">区域4,高100</div>
  <textarea id="info" cols="50" rows="20"></textarea>
<body>
显示结果为:
70
15
28
0
100
15
--------------
50
0
18
0
50
115
--------------

19,网上许多人都问,如何将一个RGB颜色转换为HTML中的十六进制颜色,我看到了一些网友的实现,例如定义一个长度为256的数组,并按照十六进制的规律将其全部初始化,还有的利用了HTML标签的一些特点,不过有一定的局限性,其实我们只要理解了RGB颜色的基本知识,转换起来是很方便的,RGB分别代表红(Red)、绿(Green)、蓝(Blue)三种基色,其中每一种基色从浅到深又可以定义256色,这样RGB总共可以表示256x256x256种颜色,而对于十六进制颜色来说,其实就是用十六进制数字来表示RGB,例如FFFFFF代表rgb(256,256,256),换算起来也很简单,就是十进制与十六进制之间的表示方法的转换,例如对于RGB颜色rgb(132,216,12),用十六进制颜色表示的计算方式为:
132转换为十六进制数字为84
216转换为十六进制数字为D8
12转换为十六进制数字为0C
因此rgb(132,216,12)的十六进制颜色就是84D80C,我们可以看一下两者的效果:
<div style="background-color:rgb(132,216,12);width:50;height:50"></div>
<br>
<div style="background-color:#84D80C;width:50;height:50"></div>
显示为:

<script>
  var hex=Integer.toHexString(253);
  document.write("<br>"+hex);//显示为FD
</script>
或者你直接使用JsJava种的Color对象:
var color=new Color(132,216,12);
var hex=color.toHexValue();//hex的值为84d80c

20,web开发过程中,经常会遇到原页面与弹出页面之间进行交互的问题,如果只是简单的变量传递,还是不难的,而我们经常遇到的一个实际场景是:例如有一个用户列表页面,点击“新建”按钮,弹出一个创建用户的页面,填写完信息后要提交表单并关闭窗口,同时列表页面中要列出新建的用户,这个时候我们一些开发人员喜欢使用的方式为:
userForm.submit();
opener.location.reload();//或者有些开发人员喜欢用opener.location=列表页面的请求url
window.close();
上面的代码有一个很明显的问题,就是如果表单提交给后台,后台还在处理,而此时原页面已经执行了重载,那么等新用户在后台存储后了,也不会反映到列表页面中了,当然刷新一个就有了,但是就达不到我们所要的效果了。下面给你介绍一种比较稳妥的方式(ajax方式就不介绍了):
先让表单提交,提交后还是回到弹出的那个页面,或者一个其它的页面,然后在该页面中做判断,如果后台信息处理成功,那么就执行原页面的重载,然后关闭窗口。
当然有些开发人员说,前面的那种方式,一直在项目中使用没有发现什么问题,那我告诉你,那是因为你比较幸运,后台处理速度很快,列表重载的时候,后台已经处理完了,但是一旦后台处理慢了,客户就该找麻烦了。

21,界面问题是当前web开发领域(不要认为只是asp、jsp和或者php等的开发,大的说可以包括ASP.NET以及J2EE等)最为棘手的问题之一,而且大部分开发人员,不懂得该如何去解决界面问题,而且经常会遇到一些不可思议的问题。其实我告诉你,界面问题的确有一些是非常奇怪的,但是不要因为这样,就不去深究问题的原因所在,我在这些年的开发中,遇到了不少的离奇的界面问题,包括自己碰到的和别人让我去解决的,不过我发现,在这些离奇的问题背后,体现的却是我们大部分开发人员,在界面能力和素养方面的一些问题,例如有些人就是太粗心,而有些人则是缺乏界面基础知识等等。成为界面高手不是目的,培养解决界面问题的能力和素养才是最关键的。

22,在连接标签中加入onclick操作是很常用的一种方式,例如:
<a href="#" onclick="window.open('yoururl')">人员管理</a>
一般情况,这种方式是没有问题,但是如果页面内容比较长,出现了上下滚动条的时候,这种方式就会出一些问题,主要是由于href的#造成的,我们知道锚的作用就是让页面定位并移动到锚处,上面的代码开发人员的意图主要是想点击的时候不要执行链接href,所以写一个#,但是#对于滚动的页面,会在执行onclick的同时,页面出现移动定位行为,这样的用户体验是很不好,解决方式有如下几种:
<a href="javascript:void 0" onclick="window.open('yoururl')">人员管理</a>
<a href="javascript:return" onclick="window.open('yoururl')">人员管理</a>
建议使用void 0方式,因为return方式,有时会影响click事件的传播,尤其是return false的时候。

23,在Window XP系统中,我们经常奇怪为什么我们使用的Javascript控制窗口尺寸和位置的一些操作,而IE竟然没有全部支持呢,例如下面的代码:
<script>
  window.open("about:blank","","width=10000,height=15000");
</script>
按道理应该弹出一个10000x15000的大窗口,然后实际上IE给我们弹出的不过是一个和浏览器尺寸大小一致的窗口,为什么会这样呢?其实我们理解微软,如果不这样限制,系统可能会因为大量的这种代码而最终崩溃,当然微软的IE也提供了配置入口,配置是否进行限制,具体入口为:

对一般站点类说,默认都是禁用的,只要打开就可以了。

24,我们页面中经常会以post方式提交表单数据,提交之后,如果我们刷新页面,IE中一般都会提示如下图所示的信息:

如果避免这种提示出现,一种是编程上去解决,即表单提交后,不要从其它窗口对该窗口继续执行location的reload方法等等,最好是使用location的href属性或者assign、replace等方法),在IE的高级选项中,也有一个条目可以设置重定向表单提交时是否给出提示信息,但是设置了之后,没有什么效果,因此也就不过多介绍了。

25,现在很流行div+css方式的布局,的确这样做界面框架的灵活性大为增加,可以说什么布局都能出的来,而且目前的ajax方式的轻量级portal框架基本上都采用的是div+css的布局方式,但是也不要过度的使用,或者什么场合下都使用,例如对于一个中大型的项目而言,要考虑的不仅仅是布局这样的事情,还要考虑界面框架的许多东西,在这种情况下,还是使用模板的方式比较好,事实上div+css是一种布局,而模板是一种“框架”,两者可以结合使用,至于能结合到什么程度,就看你的实际本领了。

26,做为一个项目经理、产品经理或者是技术总监,你应该要重视界面方面的问题了,想想吧我们现在的开发人员,大都能很快的完成后台逻辑的开发,但是到了界面展现却是捉襟见肘,界面效果和易用性做的都不到位,界面方面都调整好了,需要的时间往往并不比后台逻辑开发用的时间少多少,相信你见到过吧,为了调试一个界面中的奇怪的问题,往往会用掉一个人一两天的时间,如果再不重视界面技术的学习和素养的培养,我们的路还能走多远。

  又七七八八的为大家总结了一下我在web开发尤其是界面开发上的一些经验,这些都是摸爬滚打出来的,可以算作是经验,但不一定就特别的正确,许多东西还需要你自己去实践、检验和再总结,如果我写的这些东西,对你而言哪怕只是有一点的用处,我都是很欣慰的,另外一点我需要说的,就是我们应该逐步走出大师崇拜的阴影,不要再津津乐道于敏捷开发、极限编程等等,面对那些国外的大师,我们更为重要的是学习他们身上的精神和品质,而不是做一个忠实的传道士,对于这些精神和品质,我们中华民族实际上很早就有了,只是到现在已经少的可怜的,但并不是说我们就没有希望了,看看当今科学界和各个行业的民族精英们,看看他们骨子里面的那种精神,是很值得我们崇敬和学习的。

  我会在后面继续结合实际遇到的问题进行总结,并在合适的时候写给大家,如果你想与我联系,可以给我发email:freeeob@gmail.com  或者 zhangbo@ciksa.com,欢迎交流共享,希望中国早日富强!


评论

#  finalljx 发表于2007-10-08 13:35:52  IP: 10.1.145.*
支持一下 ,看了web开发应注意的问题1 对自己帮助甚大。

#  lenel 发表于2007-10-08 15:21:44  IP: 202.165.107.*
很多东西总结相当不错。
不过不喜欢往自己脸上贴金的做法,
哪JsJava和prototype.js类比,没意义。



#  eye_of_back 发表于2007-10-08 18:53:17  IP: 221.222.230.*
的确是有些往脸上贴金了,多谢提醒,不过我是想人们能到逐步的自立自强起来,不再依赖于国外的思想或者软件,咱们中国人曾经的那么强,我相信在适当的向国外学习和借鉴的基础上,依靠民族自身的素养,逐步壮大自己的软件产业,才是最关键的。

#  eye_of_back 发表于2007-10-08 20:26:05  IP: 221.222.230.*
我已经将第19条中JsJava和prototype.js的对比去掉了,换作了对颜色的处理,希望对您有所帮助!

posted @ 2008-04-29 13:13 珊瑚海 阅读(192) 评论(0) 编辑

http://blog.csdn.net/eye_of_back

1,document.getElementById方法只能获取到一个对象,即使有多个同名的对象,也只取第一个具有该名称的对象,例如在一个form(名称为myform)中,有三个id="mycheckbox"的复选框,那么使用document.getElementById("mycheckbox"),返回的是第一个checkbox对象,而不是返回一个数组,如果使用document.myform.mycheckbox则返回一个数组。

2,使用showModalDialog打开一个页面,则在这个页面中,对于任何链接和任何表单提交,都会在新的窗口中执行,即使你在链接或form中指定了target="_self"也是没有用的。例如使用showModalDialog打开一个test.html,在该页面有一段代码
<a href="test2.html" target="_seft">打开</a>
如果点击该链接,那么将会在新窗口中打开test2.html,至少在ie中是这样的,那么是不是就没有办法解决了呢?不是的,我们可以通过在弹出的页面的head中加入下面的代码来解决这个问题:
<head>
  <base target="_self">
</head>

3,在一个页面含有某个iframe,其id="myframe" name="myframe",此时使用document.getElementById("myframe")取到的是iframe标签对象,通过该对象可以获取iframe的各个属性,例如src、frameborder、style等等,但是不能获取到iframe所包含的子页面的各个对象。如果使用document.frames("myframe")取到的是iframe组件对象,通过该对象可以获取到iframe所包含的页面的子页面的各个对象,例如子页面的window对象,但是不能获得iframe标签得各个属性,例如上面说到的src等等。请参看如下类似代码:
1.html
<script>
  function check(){
    var obj1=document.getElementById("myframe");
    alert(obj1.src);
    //alert(obj1.window.document.myform.username.value);//Error
    var obj2=document.frames("myframe");
    alert(obj2.window.document.myform.username.value);
    //alert(obj2.src);//Error
  }
</script>
<body onload="check()">
  <iframe id="myframe" name="myframe" src="2.html" frameborder="3" style="width:300;height:200;border-width:1;border-color:red;border-style:solid"></iframe>
</body>
2.html
<body>
  <form name="myform">
    用户名:<input type="text" name="username" value="test" />
  </form>
</body>

4,在table中,如果在table中加入border="1" bordercolor="red",那么table中所有单元格都会加上厚度为1的红色边框,但是如果在table中加入css style="border-width:1;border-color:red;border-style:solid" 那么只会在整个table的最外面加上厚度为1的红色边框,分别如下图所示:

当然第一个出现了双边框,这是因为没有设置cellspacing的缘故,只要在table中设计cellspacing="0",那么就变为单边框了。

5,许多时候我们需要在页面加载时能够通过javascript去动态操作html中的一些对象,对于这些操作我们最好是在body中定义onload操作,然后在该操作中去完成这些任务,尽量避免在html中嵌入script执行代码,因为对于比较大的页面,当这些脚本执行的时候,页面往往还没有加载完毕,因此许多页面对象还没有被生成,此时动态去改变很可能会报异常。

6,有时候我们需要在iframe子页面中调用父页面的javascript函数,例如在父窗口中定义了一个函数如下:
<html>
  <script>
    function loadImage(){
       //...
   }
 </script>
<body>
//...
</body>
</html>
那么在iframe子页面中可以通过parent.loadImage()来实现调用,这也说明用户在页面定义的所有javascript函数都属于window对象之下。那么在父窗口如何调用子窗口中的函数呢,应该很简单了,就是获得子窗口对象,然后调用子窗口对象的window对象下的这些函数即可,例如iframe的name为myframe,在子窗口定义了一个函数getUserName,那么父窗口中的调用方式为document.frames("myframe").getUsername();另外对于父窗口调用子窗口中的方法,还要注意一个问题,就是子窗口的加载有时候会比较慢,如果子窗口正在加载,那么此时它的各种页面对象都不存在,那么当在父窗口调用子窗口的方法时,为了保险可以使用借助setTimeout来实现异步调用,即通过setTimeout指定一定时间之后(例如100ms),再执行调用,调用执行总是判断子窗口页面是否加载完毕,如果没有加载完毕,则继续使用setTimeout方法,循环往复直到子窗口被完全加载,然后执行子窗口的函数调用。既然这里解释了窗口间的异步调用,后面就不专门解释了。

7,在一个网页中如何最小化窗口,当然你可能会说,网页的右上角不是有最小化、最大化和关闭三个按钮吗,当然了这里说这个问题是指,如果不点击网页右上角的最小化,如何实现网页的最小化操作,例如有些项目中,用户需要办公界面是全屏化的,这意味着网页自己提供的许多操作都不可见,更不用说去操作了。在网络上我们搜索最小化的解决方式,我们会发现千篇一律的使用如下的方式实现:
<object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"> 
<param name="Command" value="Minimize"></object>
<input type=button value=最小化 onclick=hh1.Click()> 
在win98和windows2000中这个方式可能是可以的,但是在windows XP中却是不再支持了,不仅如此在windows XP中对javascript不少函数做了限制。那么在XP中如何实现最小化呢,一个可以实现的方式就是自己写一个activeX控件,这个是在项目中证明可以实现的。(不要认为activeX控件很难写,也不要以为activeX控件用户不接受,在实际的项目中如果用户使用的都是ie,那么用户一般是会接受的,当然这里的项目最好是内网办公项目,对于公网项目来说,用户接不接受就很难说了)

8,注意td中nowrap的使用,这个属性是很有用的,例如如果一个td中含有多张图片,那么如果不加入nowrap,那么很可能这些图片会由于其它的td的挤压而产生细微的上下错位,这表现的页面上就是某处出现了一条横向的细缝。这一点很重要,页面中许多非常奇怪的现象都与此有关。

9,对于showModalDialog弹出的页面,不能使用右键菜单,也不支持F5和ctrl+r刷新,如果此时修改弹出页面的内容,那么必须关闭该窗口,然后重新弹出才可以。另外,对于许多web服务器,由于服务器都设置有缓存,如果修改了弹出页面的内容,那么许多时候只是关闭弹出页面还是不够的,往往还需要关闭弹出该页面的那个页面才可以。在这里多说一句,web开发许多奇怪的页面现象都和web服务器的缓存有着很大的关系,因此出现问题时考虑一下是否是由于服务器的缓存所致。

10,我们喜欢在form中定义onsubmit操作,主要是为了在表单提交之前可以做一些有意义的操作,例如检查输入域的有效性等等,但是一定要注意,如果我们通过点击该form中的submit按钮(type=submit或type=image)提交表单,那么该onsubmit操作会被执行,但是如果通过document.formName.submit()提交表单,那么此onsubmit操作将不被执行。

11,许多时候我们修改了页面的内容,但是我们刷新页面或重新打开该页面,却看不到修改的效果,除了前面提到过的showModalDialog和缓存的情况要考虑外,还要检查一下是否改对了地方,即你修改的那个页面是否是服务器上的那个页面,有可能你修改了其它地方的一个页面,如果不是这个原因,那么再进行其它方面的检查。

12,在没有系统规划好之前,请不要在css中定义html标签的统一行为,即下面的形式:
<style>
  TABLE{font-size:11pt;color:black;}
  INPUT{border-width:1;border-color:pink;border-style:solid}
</style>
因为一但定义了这些标签的属性,那么这将会影响页面中所有的这些标签属性,尤其在一些公用的css文件中,尽量不要定义html标签的统一行为。当然如果经过了系统的良好的规划,那么这样做将是非常好的,只是在国内在css上经过良好规划的并不多,因此虽然我们见到许多项目和产品中对html标签做了许多css的定义,但是真正起到作用的并不多。

13,在html标签中有许多属性的名称都是复合词,例如borderColor、frameBorder、readOnly等等,注意这些复合词在html的书写,一般来说我们在html标签中写为borderColor和bordercolor,各个浏览器的解析都会通过,但是我们在使用javascriopt引用这些属性时却需要注意了,一定使用正确的属性名称,严格来说,对于复合词而言,除了第一个有意义的词之外,其它任何有意义的词的首字母都要大写,例如对于上面列出的三个属性的引用,一定要使用borderColor、frameBorder、readOnly的形式。
<input type="text" id="myinput" readonly />
<script>
    var flag=document.getElementById("myinput").readOnly;//正确的方式
    //var flag=document.getElementById("myinput").readonly;//错误的方式
</script>

 14,我们知道当使用浏览器的菜单“查看”->“文字大小”来改变文字的显示时(或者有些浏览器也可以使用ctrl+滚轮键),网页中的文字的字号会发生相应的变化,如果我们在网页中的文字块中定义了style="font-size:10pt",那么这些文字块中的文字的大小将是固定的了(注意在<font/>标签定义size属性是不能固定字号的),我想这一点多数人都应该知道的。但是我们使用中有时会出现一种非常奇怪的现象,例如下面的一段代码:
<table><tr><td>
<div style="font-size:10pt;border-width:1;border-color:red;border-style:solid">
  这是上面
</div>
<br />
<div style="font-size:10pt;border-width:1;border-color:green;border-style:solid">
  这是下面
</div>
</td></tr></table>
我们看一下在字号显示“最大”和“最小”下的差别:

从上图我们可以看到字号我们是固定住了,但是table的高度却会随着查看方式的不同而发生变化,这是为什么呢?原因就在于td当中的那个<br />,我们知道<br />是表示段内换行,但是要注意在网页中所谓的行也是有一定的默认高度的,而且这个高度随着查看方式的不同而发生相应的变化,因此如果我们想固定上面table的高度不发生变化,有下面两种方式:
方式一:在table标签中加入字号限制例如<table style="font-size:10pt"...
方式二:在<br />中加入字号限制例如<br style="font-size:10pt" />...
如果你是一个web开发人员,你可以试着使用ctrl+滚轮键改变网页查看文字的大小,你会发现不少页面都存在这个问题的。

15,网页中定位对象的方式有许多种,下面先简单总结一下,以后再专门写这个方面的文章的:
1)页面内通用定位方式(这些定位方式适用于后面其它元素的定位)
document.getElementById(objId);//通过对象的id获取对象,这个是各个浏览器都支持的,返回一个对象
document.getElementsByName(objName);//通过对象的name获取对象,这个是各个浏览器都支持的,返回一个数组
document.getElementsByTagName(tagName);//通过标签名称获取对象,这个是各个浏览器都支持的,返回一个数组
document.all.objId;//通过对象id获取对象,这个是ie支持的,返回一个对象
document.all(objId);//通过对象id获取对象,这个是ie支持的,返回一个对象
document.layers.objId;//通过对象id获取对象,这是Netscape支持的,返回一个对象
document.layers(objId);//通过对象id获取对象,这是Netscape支持的,返回一个对象
window.objName;//通过对象名称获取对象,至少在ie中如此
objName;//通过对象名称获取对象,至少在ie中如此
2)页面内集合元素的定位方式
我们知道在页面中有许多集合,例如form、frame、image等等,引用这些集合中某个对象的方式为,举其中一个为例,其它都差不多,以form为例:
document.formName;//通过表单name获取表单对象
document.forms[index];//通过索引获取表单对象,浏览器会按顺序将页面中所有的表单集合城数组,可以通过下标引用
document.forms(formName);//通过表单name获取表单对象
3)定位子窗口的方式(定位子窗口对象,不是标签对象,见前面3中的说明)
子窗口是指页面中frame或iframe窗口,定位方式为:
document.frames[index];//索引定位方式
document.frames(frameName);//通过名称定位
window.frameName;//通过名称定位
frameName;//直接通过名称来定位
4)在子定位父窗口的方式
通过关键字parent来引用即可,同理parent.parent则表示父父窗口,top则表示最上层窗口。
5)原窗口定位open弹出窗口的方式,例如下面代码:
window.open("test.html");
这里我们要知道window.open将会返回一个弹出窗口的句柄,即可以如下:
var owin=window.open("test.html");
owin即代码弹出窗口对象,通过改对象可以引用到弹出窗口的各个对象。
6)原窗口定位showModalDialog弹出窗口的方式,例如:
window.showModalDialog("test.html");
注意showModalDialog与open不同,open弹出窗口后,window.open后面的代码可以继续执行,而showModalDialog弹出窗口后,原页面被阻塞,即window.showModalDialog后面的代码不被执行,直到用户关闭了弹出窗口才会继续往下执行,但这时因为已经关闭了弹出窗口,所以已经无法再对该窗口进行引用。
7)open弹出的窗口对原窗口的定位方式,这个我们一般都知道,在弹出窗口中使用opener即可。
8)showModalDialog弹出的窗口对原窗口的定位方式,这个不是使用opener,而应该在弹出窗口中使用parent。

16,编写页面代码尽量使用标准的html、css和javascript,不要以为只要在ie上通过就可以了,要注意最近浏览器市场已经开始发生变化了,不知道你是否听说过Firefox2.0,它的用户量已经不在ie之下了,至少你的代码要在ie和Firefox上都通过才可以,另外现在linux越来越吃香,保不准几年后我们的许多客户都开始使用linux,到那个时候,我们将不得不对原来已经完成的项目进行维护,与其这样的后果,还不如从现在开始就使用标准为好,不要认为跨浏览器是很虚的话题,觉得没有必要,要知道这已经不是几年前了,现在形式和市场都在发生变化,我们的思想也该变一变了。

17,我们的产品或OA系统往往会有许多模块,例如用户管理、发文流程、物品管理等等,我们在为这些模块命名时往往都是不太讲究的,没有注意名字的结构、字数等的统一,例如在个人事务模块下面有三个子模块,名称分别如下:待办事项、已办事项,维护个人信息。对于字数而言我们往往不会苛求太多,但是对于词的结构,我们还是要讲究的,例如上面的三个模块,前两个是名词结构,而后一个是谓词结构(动宾结构),这是不太妥当的,也许你觉得这有些吹毛求疵,当然大多数项目中不会要求这么严格,但是有些客户的确会有这样的要求,另外对我们自己而言,这也体现了我们做事认真、一丝不苟的品格和态度。

18,图标与文字的配比要合适,这不仅要求图标能够正确显示文字的意思,而且还要求图标不能盖过文字的显示与含义,即图标太显眼而文字无足轻重的情况需要避免,例如下面的情况就是不太合适的:
 用户管理
之所以不合适,主要是因为图标的含义与用户管理关系不大,图标的含义更接近“XX编辑”的意思,和用户管理基本没有什么联系。

19,在用户登录和表单处理页面,我们要处理用户按enter键的情况,即用户按enter键也要触发提交事件,不要只有用户点击“登录”或“提交”按钮才触发提交操作。

20,如果我们在页面中使用<a />标签,那么默认情况,当鼠标移到该链接时,鼠标自动会变为手的形状,许多时候我们希望鼠标移动到其它非链接的区域,也希望鼠标变为手的形状,我们一般的处理方式为在该区域的style中加入cursor属性,如下:
<span style="cursor:hand" onclick="myfunc()">下一页</span>
或者使用:
<span style="cursor:url('http://webme.bokee.com/inc/mouse118.cur')" onclick="myfunc()">下一页</span>
但是要注意,只有在ie中才支持cursor:hand,在firefox2.0中的cursor中是没有hand的,像wait、help等都是支持的,另外firefox中也不支持cursor:url方式。

21,我们有时想通过javascript进行跨域页面的调用,不过出于安全性的考虑,各个浏览器一般都是不支持的,例如下面的代码:
<iframe src="http://www.google.com"></iframe>
<script>
  setTimeout("document.frames[0].window.location.href",3000);
</script>
使用setTimeout是为了可以让iframe子页面可以加载完毕,上面的调用会报安全性警告,例如在ie如下:



那么是不是说只要是跨域就能不能进行javascript访问了呢?不是的,一种比较常用的办法就是设置document.domain属性,这种方式的描述如下:
假设有两个页面
test1.html 所在域:aaa.maindomain.com 访问协议:http 端口:8080
test2.html 所在域:bbb.maindomain.com 访问协议:http 端口:8080
满足上面条件的两个页面test1.html、test2.html是可以通过javascript相互访问的,上面的条件即为两个页面位于同一个基础域(例如上面同为maindomain.com),遵循同一个访问协议和端口(例如上面同为http 8080)。只要在这样的两个页面中都设置document.domain为所在基础域名,就可以相互调用了,例如:
test1.html 所在域为aaa.mydomain.com
<script>
  document.domain="mydomain.com";
</script>
<iframe src=http://bbb.mydomain.com/test2.html></iframe>
<script>
  setTimeout("document.frames[0].window.location.href",3000);
</script>
test2.html 所在域为bbb.mydomain.com
<script>
  document.domain="mydomain.com";
</script>
...
这样一来,test1.html的调用就是可以的了。一般来说跨域调用的场景发生在集团型企业项目或多机构的政务项目中,而对于这种类型的项目,它们的基础域基本上是相同的,只是三级域名不同,因此可以使用上面的方式来进行跨域调用。

22,你会页面中的javascript调试吗?也许你还不会使用ie或firefox提供的页面调试器或插件,那么没有关系,至少你懂得一种最基本的调试:alert调试,不要认为这是一种很土或很傻的方式,很多时候这种方式都很非常有用的,对于一段很长的javascrip代码,从头到尾加入几个alert,那么立即就能定位错误的大概位置,当然使用调试器的断点也可以很快定位,只是说alert也是一种不错的方式。当然还是希望你能够掌握更为高级的调试器的使用,毕竟调试器带给我的功能更强大。

23,我们许多时候编写完网页之后,发现最终的显示效果和我们想象的不太一样,这有些时候是由于浏览器的不同造成的,但除此之外,我们如何具体定位到底是页面的哪块代码导致不太理想的页面效果呢?当然你可能会使用Dreamweaver或Frontpage打开出问题的页面,然后查找原因,但是这些所见即所得的网页设计器,并非我们想象的那么完美,例如明明在设计器种预览很好的效果,到了真实环境中页面竟然出现了错位等等,这里和你介绍一种非常不错的css的调试方式,这里就不具体说了,请参看我新写过的一篇文章【css在html中的调试作用

24,网页打印我们都知道可以调用window.print函数,那么如果想打印iframe子窗口中页面呢,如果你只是获得子窗口对象,然后调用子窗口对象的print方法,此时打印机打印出却不是子窗口页面的内容,而是父窗口页面自身,为什么会这样呢?原来(至少在ie中如此)在父页面调用子窗口的print函数时,因为此时焦点还在父窗口之中,所以打印机此时会将获得焦点的窗口进行打印,我们在打印子窗口之前,只需做一件事即可完成对子窗口的打印,如下代码:
<html>
 <head>
  <script>
    function myprint(){
       document.frames("myframe").window.focus();
       document.frames("myframe").window.print();
   }
  </script>
 </head>
<body onload="myprint()">
  <iframe name="myframe" src="test2.html"></iframe>
</body>
</html>

25,网页切图许多人都习惯于网页三剑客的配合使用,网页三剑客就是网页开发者都熟悉的Dreamweaver、Fireworks和Flash,一般我们使用使用Flash或Fireworks将动画或图切分后输出成为html页面,然后通过Dreamweaver编辑输出后的页面,这是我们网页切图常用的配合方式,但是通过使用比较发现,在图片的切分方面,使用Photoshop要好于Fireworks,Photoshop不仅定位更加精确,而且由于自身是平面设计的标准,因此它提供了许多图片编辑的其它功能,这要比fireworks强大得多。目前专业的网页设计师都在开始或一直使用Photoshop进行网页设计并切分后输出成为HTML页面。如果你是三剑客的爱好者也没有关系,你可以使用一下看看效果如何,总之我从2000年就开始使用三剑客,现在才逐渐认识到Photoshop已经不仅仅是平面设计的标准了。

26,在javascript中有一个方法可以列出当前对象所支持的所有属性、集合和事件,通过使用in关键字来实现,如下样例代码:
var str="";
for(var i in document){
    str+=i+"\n";
}
alert("document's all attributes:"+str);

27,在一个名称为myform的表单中,含有一个名称为mychckbox的复选框,那么document.myform.mycheckbox所取到的是那个复选框对象,那么此时调用document.myform.mycheckbox.length是错误的,如果该表单中含有多个名称为mycheckbox的复选框,那么document.myform.mycheckbox返回的是一个数组,此时调用document.myform.mycheckbox.length就是正确的。单独说这个问题,可能感觉比较简单,但是在实际应用中我们经常会犯与此相关的错误,如下图所示:

上图是我们在应用中经常遇到的“增、删、改”的逻辑,我们在其中经常会对复选框做操作,经常会使用类似document.myform.mycheckbox.length的方式,一般情况不会报错,这主要是因为在我们的列表中一般来说都不会只有一条记录,但是当列表中只有一条记录的时候(尽管这种时候不常见),这样引用就会报错,因为此时document.myform.mycheckbox返回的不是一个数组,则对length的引用就没有意义了,这种错误说起来很容易,但是在编程时往往就会忽略,因此在编程时我们建议如下方式:
if(document.myform.mycheckbox.length){
  //...
}else{
  //...
}

28,在ie中有一个很特别的css语法,如果你听说过,那说明你的积累真是太丰富了!在css中有一种给汉语注音的语法,如下所示:
<style>
    ruby{font-size:13pt;} 
    rt{font-size:18pt;color:red}
</style>
<ruby>你知道这个语法吗?<rt>ni zhi dao zhe ge yu fa ma</rt><br>
不知道<rt>bu zhi dao</rt>   
</ruby>
你运行这段代码看看什么效果(要在ie中运行),我这里效果如下:

29,我们项目中经常会遇到页面打印的需求,许多时候用户需要只打印页面某一部分,如果直接调用window.print则打印的是整个网页的内容。解决办法不外乎两种,第一种方式是将整个页面分为几个部分,将需要打印的部分放在其中的一个部分,然后定义onbeforeprint和onafterprint两个操作,即打印之前将不要打印的部分隐藏,打印之后将隐藏的部分显示,类似代码如下:
<script>
   function beforePrint(){
       document.getElementById("hidden1").style.display="none";
       document.getElementById("hidden2").style.display="none";
   }
   function afterPrint(){
       document.getElementById("hidden1").style.display="block";
       document.getElementById("hidden2").style.display="block";
   }
   document.onbeforeprint=beforePrint;
   document.onafterprint=afterPrint;
</script>
<div id="hidden1" style="display:block">
这里不需要打印
</div>
<div id="printDiv" style="display:block">
这里需要打印
</div>
<div id="hidden2" style="display:block">
这里不需要打印
</div>
<input type="button" value="打印" onclick="window.print()"/>
第二种方式是将需要打印的部分放到iframe之中,然后将焦点移到子窗口,然后调用子窗口的print方法即可。

30,Javascript中的数组和我们一般的编程语言中的数组是不太一样,一般语言中数组的长度是固定的,有些语言中数组中的数据类型也要求是一样的,但是javascript数组却不受这些限制,在javascript中数组基本上是没有长度限制的,而且类型也没有限制,例如下面的一些使用方法:
var arr=new Array();
arr[1000]="ok";
arr[300]=255;
arr[200]=new Date();
var date=arr[200];
alert(date.getTime());
因为数组的这种机制,我们可以使用数组实现许多数据结构,例如列表、哈西表等等。

31,对于XML的处理一般情况下都是在服务器端处理的,例如在Java中有W3C、JDOM、XPath等许多xml的解析器,但是现在许多时候我们需要在浏览器端处理xml字符串,目前在ie和netscape中都有针对xml字符串的解析,如果你喜欢使用,也没有什么关系,不过对于Java程序员,我给你介绍一个完全按照W3C Document API实现的XML解析器,相信你会非常喜欢的,因为完全是Java的风格,请从 http://download.jsjava.com/ 下载jsjava0.91,在其中的src/jsorg/w3c/dom下有XML各个对象的实现,在页面中只需引用其中的xmlp.js和i18n.js即可,具体使用可以参考里面的例子:位于下载包的examples/XMLParser/XMLW3CParser下面,也可以直接访问:http://jsjava.sourceforge.net/examples/XMLParser/XMLW3CParser/W3CXMLParser.html 查看例子。

32,一段文本的首行文本缩进两个汉字,这是中文段落的格式要求,我们可以通过在首行加入多个&nbsp;来实现,不过还是建议使用css的标准属性text-indent,例如下面的代码:
<p style="text-indent:28;font-size:10pt">
这是一段文本,请注意它的格式,<br>
你看到了什么效果?如果你看到首行<br>
缩进了,那么说明起作用了。
</p>
显示效果如下:

33,在Javascript中字符串的替换函数为replace(regexp, newSubStr),其中第一个参数是一个正则表达式,但是我们在实际使用中,往往习惯使用为一个字符串,这虽然不会报错,但是得到的结果往往是不正确的,例如下面的例子:
var str=“ abbbbacc”;
var rs=str.replace(“a”,”0”);
(A)0bbbbacc (B)0bbbb0cc
正确答案是A,当然A可能不是你想要的结果,你想要的结果是字符串中所有的“a”都被替换为“0”,可是上面的使用方式只能将第一个“a”替换为“0”,正确的使用方式,在第一个参数中输入一个正则表达式,如下所示:
var str=“ abbbbacc”;
var rs=str.replace(“/a/g”,”0”);//注意如果第一个参数为/a/,结果也是不正确的。
(A)0bbbbacc (B)0bbbb0cc
这样的话答案就是B了,如果你不明白/a/g是什么意思,那么你就需要对Javascript的正则表达式好好学习了,具体可以参看我以前写过的一篇文章:http://blog.csdn.net/eye_of_back/archive/2006/07/14/922667.aspx

34,无论你使用的是ASP,还是PHP,或者JSP,都不建议在页面代码中夹杂着大量的业务逻辑代码。我们应该将业务逻辑代码封装到应用服务器层或者说业务层,web端只是进行调用。在JSP和PHP中我们可以将业务逻辑封装到BO(业务对象)中,由于支持类、接口等一套面向对象的机制,使得这种封装显得很容易,对于ASP,由于ASP.NET和C#的兴起,使得它对业务封装也变得相当方便。虽然我们都懂得服务器的三层架构,但是我们发现许多的项目之中,开发人员仍然在页面中直接编写业务逻辑,甚至直接访问数据库,面对这种情况,不能不说我们的项目管理是存在很大的问题的,我们的项目经理和程序设计师们,我们应该好好反思一下了。

35,有些时候我们在<a/>标签的href中直接加入javascript代码,通过window.open来打开一个自己可以控制许多属性的窗口,例如下面的代码:
<a href="javascript:window.open('http://www.google.com');">打开Google</a>
当我们点击链接后,确实弹出了Google的页面,但同时原页面却变为了下面的样子:

这种情况相信有些人遇到过,解决方式如下:
<a href="javascript:window.open('http://www.google.com');window.opener=null;window.close()">打开Google</a>
但是为什么前面的那种方式就会出现那种情况呢,其实只要做个简单实验就会明白了,你运行一下下面的代码,点击链接看看会出现什么结果:
<a href="javascript:window">打开Google</a>
实验后你会发现,点击链接后页面出现的结果与上面那种结果相同,然后你再实验一下下面的代码:
<a href="javascript:'test'">打开Google</a>
点击链接后,你会发现页面中会显示test字样。可见对于类似
<a href="javascript:js代码">点击</a>
的代码,如果js代码执行完毕后返回一个对象,那么页面内容会被冲掉,然后将该对象的描述输出到页面中,我们知道window.open方法返回的是弹出的页面的窗口对象(window),因此javascript:window.open将会在弹出一个窗口的同时,原页面会冲掉原有内容并将返回的window对象输出到原页面中。如果在window.open后面加入window.opener=null;window.close(),则弹出窗口后,返回给原页面的对象为空,则原页面不执行任何其它操作。

 

posted @ 2008-04-29 13:12 珊瑚海 阅读(176) 评论(0) 编辑


 jQuery 具有一个相当强大的选择器引擎,提供了完整的选择器语法,允许我们选择几乎所有的元素组合。jQuery 的选择器语法主要是基于 CSS3 和 XPath 的,对 CSS3 和 XPath 了解越多,使用 jQuery 时就越显得心应手。有关 CSS 和 XPath,请参阅以下链接:

值得注意的是, CSS3 并没有得到现今所有浏览器的支持,因此我们很少使用它。然而,我们仍然可以在 jQuery 中使用 CSS3 选择元素,因为 jQuery 具备自己的自定义选择器引擎,并且实现了对 CSS3 的支持。

想了解 jQuery 选择器更多信息,可以访问 jQuery 的官方文档有关 Selector 的部分。下面,在原官方文档的基础上作一些简单的翻译和说明。

1. CSS 选择器(CSS Selectors)

jQuery 完整地支持 CSS 1-3,并且可以在(选择器)表达式里加入自定义的 CSS-like (和xPath)。

1.1 jQuery 支持的 CSS 选择器语法

  • * 任何 element
  • E 类型为 E 的所有element(其实 E 可以是任何 element)
  • E:nth-child(n) 一个类型为 E 的 element,它是其父 element 的第 n 个子 element
  • E:first-child 一个类型为 E 的 element,它是其父 element 的第一个子 element (相当于E:nth-child(0))
  • E:last-child 一个类型为 E 的 element,它是其父 element 的最后一个子 element
  • E:only-child 一个类型为 E 的 element,它是其父 element 的唯一子 element
  • E:empty 一个类型为 E 的用户界面(UI) element,它没有子 element(包括 文本 element)
  • E:enabled 一个类型为 E 的用户界面(UI) element,它被设置为禁止(disabled)
  • E:disabled 一个类型为 E 的用户界面(UI) element,它被设置为允许(enabled)
  • E:checked 一个类型为 E 的用户界面(UI) element,它处于选中(checked)状态(适用于单选按钮和复选框)
  • E:selected 一个类型为 E 的用户界面(UI) element,它处于被选择(selected)状态(在选择范围内,有一个或多个可供选择的 element )。注意:selected 属性并不在 CSS 的规范内,但jQuery 提供内部支持
  • E.myclass 一个类型为 E 的 element,它的 class 类是“myclass”
  • E#myid 一个类型为 E 的 element,它的 id 是“myid”
  • E:not(s) 一个类型为 E 的 element,并且结果集中的 element 不匹配(不包含)选择器 s(用作过滤
  • E F 一个类型为 F 的 element,它是类型为E 的 element 的子孙 element(注意是子孙 element)
  • E > F 一个类型为 F 的 element,它是类型为E 的 element 的子 element(注意是 element)
  • E + F 一个类型为 F 的 element,它是紧跟在类型为E 的 element 后面的一个兄弟 element(注意 F 是 E 的兄弟节点,并且是紧跟随其后的一个
  • E ~ F 一个类型为 F 的 element,它是类型为E 的 element 后面的一个兄弟 element(注意 F 是 E 的兄弟节点,并且位置在E 的后面)
  • E,F,G 一个类型为 E 的 element,一个类型为 F 的 element,一个类型为 G 的 element(用于选择多个 element)  

    1.2 jQuery 支持,但(跟 CSS 规范)有所不同的选择器语法

    不同之处是必须在属性名前加上符号“@

    • E[@foo] 一个类型为 E 的 element,它具有属性“foo”
    • E[@foo=bar] 一个类型为 E 的 element,它具有属性“foo = bar”
    • E[@foo^=bar] 一个类型为 E 的 element,它具有属性“foo“,并且其属性值是以”bar“开头的
    • E[@foo$=bar] 一个类型为 E 的 element,它具有属性“foo“,并且其属性值是以”bar“结尾的
    • E[@foo*=bar] 一个类型为 E 的 element,它具有属性“foo“,并且其属性值包含”bar“
    • E[@foo=bar][@baz=bop] 一个类型为 E 的 element,它具有属性“foo = bar”和属性”baz = bop“

    :以上的“bar”和“bop”均为字符串。

    1.3 jQuery 不支持的选择器语法(略)

    因为没什么实际的作用,所以这里也不作赘述,想了解详情的可以参阅官方帮助文档

    1.4 Contex 和 Anchoring

    可以设置 contex 来 anchor(定位) 选择器,这也是 jQuery 跟 CSS 规范的一个不同之处。用户可以使用语法: $(expr, context) 来设置 context root。默认的 context root 是整个文档。

    2. XPath 选择器(XPath Selectors)

    XPath 也是 jQuer 支持的选择器语法之一。jQuery 支持基本的 XPath 语法下面以一些例子作说明。

    2.1 定位路径(Location Paths)

     

    • 绝对路径,相对于整个 HTML 文档
     $(”/html/body//p”) $(”body//p”) $(”p/../div”)
    • 相对路径,相对于设置的 context node “this”
     $(”p/*”, this) $(”/p//a”, this)

    2.2 支持 Axis 选择器

     

    • //” : 子孙 elements (div 所有类型为 p 的子孙 elements)
     $(”/div//p”) $(”//div//p”)
    • /子 elements (div 所有类型为 p 的 elements)
     $(”//div/p”)
    • ~兄弟 elements (div 所有类型为 form 的兄弟 elements)
     $(”//div ~ form”) 
    • ““..父 elements (div 的父 element 下的类型为 p 的子 elements)
     $(”//div/../p”)

    2.3 支持谓词语法(Predicates)

    • [@foo] 具有属性“foo”
     $(”//input[@foo]”)
    • [@foo=’test’] 具有属性“foo = ‘test’”
     $(”//a[@foo = ‘tsxt’]”)
    • [Nodelist]子孙 elements 匹配 Nodelist(用于过滤)
     $(”//div[p]”) $(”//div[p/a]”)

    2.4 jQuery 支持,但(跟 XPath 规范)有所不同的谓词语法(Predicates)

     

    • [last()] or [position()=last()] becomes :last(选择结果集中的最后一个 element)
     $(”p:last”)
    • [0] or [position()=0] becomes :eq(0) or :first(选择结果集中的第个 element)
     $(”p:first”) $(”p:eq(0)”)
    • [position() < 5] becomes :lt(5)(选择结果集中索引大于5的 elements)
     $(”p:lt(5)”)
    • [position() > 2] becomes :gt(2)(选择结果集中索引小于2的 elements)
     $(”p:gt(2)”)

    :“becomes” 前面的是 XPath 的 predicates 语法,后面是等价的 jQuery 语法。

    3. jQuery 自定义的选择器(Custom Selectors)

    jQuery 具有一些自定义的选择器语法,这些语法虽然并不在 CSS 和XPath 规范之内,但它们相当的便捷,所在 jQuery 将它们囊括进来。

    3.1 自定义选择器(Custom Selectors)

     

    • :even 结果集中其索引为偶数(双数)的 elements
    • :odd 结果集中其索引为奇数(单数)的 elements
    • :eq(N) and :nth(N) 选择结果集中索引为 N 的 elements
    • :gt(N) 选择结果集中索引大于 N 的 elements
    • :lt(N) 选择结果集中索引小于 N 的 elements
    • :first 选择结果集中的第一个 element (相当于 eq(0) 或者 nth(0))
    • :last 选择结果集中的最后一个 element
    • :parent 在结果集中选择 elements,它必须具有子 elements(包括文本节点)(跟 :empty 相反)
    • :contains(’test’) 选择结果集中包含有指定文本的 elements
    • :visible 选择所有可见(visible)的 elements( display 属性的值等于 visible、block、inline,或者 visibility 属性的值等于 visible,不包括 hidden 类型的 elements(关于 hidden 类型,如<input type=”hidden” …>))
    • :hidden 选择所有隐藏(visible)的 elements( display 属性的值等于 none,或者 visibility 属性的值等于 hidden,不包括 hidden 类型的 elements(关于 hidden 类型,如<input type=”hidden” …>))

    例子:

     $(”p:first”).css(”fontWeight”,”bold”); $(”div:hidden”).show(); $(”/div:contains(’test’)”, this).hide();

    3.2 表单选择器(Form Selectors)

    • :input 选择所有表单 elements(input, select, textarea, button)
    • :text 选择所有文本域 (type=”text”).
    • :password 选择所有密码域 (type=”password”).
    • :radio 选择所有单选按钮 (type=”radio”).
    • :checkbox 选择所有复选框 (type=”checkbox”).
    • :submit 选择所有提交按钮 (type=”submit”).
    • :image 选择所有图像域 (type=”image”).
    • :reset 选择所有重置按钮 (type=”reset”).
    • :button 选择所有按钮 (type=”button”).
    • :file 选择所有 <input type=”file”>.

    :hidden 也是可用的,在上面的3.1 节有介绍。

    建议在使用表单选择时提供一个 context root,例子:

     $(’#myForm :input’)
     $(’input:radio’, myForm)

    上面最后的一行语句将会选择所有的“myForm”表单里的所有单选按钮,相当于[@type=radio](即 $(”[@type = radio],myForm”)),但用表单选择器会稍微快点,尤其对于大型的表单。

    3.3 更多选择器

    jQuery 选择器可以通过第三方的插件来扩展:

    参考资料

    http://docs.jquery.com/DOM/Traversing/Selectors

posted @ 2008-04-29 13:01 珊瑚海 阅读(212) 评论(0) 编辑