本文介绍了IE和Navigator两种浏览器对DHTML标准实现的差异,特别是如何编写Navigator中运行的DHTML程序。
DHTML(Dynamic HTML)是W3C组织提出的一种新的规范,它对原有的HTML做了许多扩充,并结合Javascript,使得静态的HTML页面产生了许多动态效果,例如菜单的展开和收起,页面元素的外观动态改变等。IE 4.0以上,Navigator 4.0以上的版本都支持这个标准。但是,不同的浏览器厂家对它都做了不同程度的扩充。以最流行IE的和NS为例,IE的实现更接近于W3C的方案,而NS,说实话,与W3C的方案差异很大,而且并没有完全实现,甚至可以说是另一套方案。笔者在初识DHTML时,按照书上讲的编写了几个小程序,在IE上一试就通,而在NS上可以说费尽了周折才逐渐找到解决方案。由于市面上很少有讲述NS的DHTML实现方案的书(大概NS由于的实现不符合标准),而真正的商业网站至少应同时支持IE和NS这两种主要的浏览器,我愿意把我的一些心得写出来与大家共享,使大家不必再走我走过的弯路。对于二者的实现相同的部分,本文作一简略介绍,您若有兴趣可参考有关书籍或网上资源。
DHTML实际上由三两部分组成:CSS(Cascade Style Sheet,级联样式表),层(Layer)和Javascript。
所谓CSS,概念上类似于C++中的类,在类定义中指明元素的外观样式,如字体,颜色,大小等等,页面中的任何一个HTML元素如被指定属于这个类,就自动拥有该类的特性;还可以为某种HTML元素定义样式,这样页面中的所有这种元素都有了同样的外观。如果将这样的样式定义存在一个单独的.css文件中(就象C++那样将类定义存在 .h文件中),再在页面中将其包含进来,则一个网站的所有页面就有了同样的外观。IE和NS对CSS的实现基本相同,在此就不再详细介绍了。
两者的差异主要体现在层的实现上。所谓层,就是页面上的一块区域,其中可以包含任何的HTML元素,通过改变层的属性,其间的元素可以跟着出现,消失,更改,移动等。 在IE中,层依靠<DIV></DIV>和<SPAN></SPAN>来实现,两者基本相同,通常<DIV>用于较大的层,<SPAN>用于较小的层,并且<DIV>在实现的层后面加上一个回车换行,而<SPAN>不加。它的语法如下(二者相同):
<div id=layername style="style definition">Layer content</div> 或
<div id=layername class="classname">Layer content</div>
其中style definition是一组有分号隔开的样式定义,常用的有以下几种:
position:其值可以为absolute和relative,所谓absolute(绝对定位),就是层的内容不必按照出现的先后次序在浏览器上依次排列,而是可以像素为单位定位到浏览器用户区域的任意位置;而relative(相对定位)则是层按照相邻的内容依次排列。
left,top,width,height:指层的左上角坐标以及它的宽度和高度。
z-index:由于层可以被放置在页面的任何位置,当它与其它内容重合时,z-index值大的显示在上面,所有层的z-index值为1。但是在NS中,所有的表单元素(文本框,列表框,按钮等),只要是可见的就无法被遮住,而无论z-index值是多少。因此在设计页面时,要注意不要使动态出现或隐藏的元素(例如弹出式菜单)的位置上放置表单元素。
Visibility:指明层是否可见,通过在程序中动态改变这个值,可以实现层的出现和消失,比如下拉菜单就要依靠它来实现。它的三个候选值为:inherit,可见性与父元素的可见性相同;visible,可见(在NS中是show);hidden,不可见(在NS中是hide)。
NS同样支持这两个标记,但是支持得很不好,经常出现一些莫名其妙的错误,我想这可能是出于策略上的考虑,而不见得是NS的产品质量不好。NS引入了另两个标记,<layer>和<ilayer>,<layer>用于绝对定位,<ilayer>用于相对定位,因此在这两个标记的样式定义中没有position属性。
两个浏览器对层的不同实现体现在以下几点:
1. 层的引用。在IE中,页面上的每个可编程元素(不仅是层,还包括其它任何指明了ID值的元素,详见下文)都是document.all集合的一项;而在NS中,页面中每个层,无论是用上面四个标记中的哪个定义的,也无论是绝对或是相对定位,都是document.layers集合的一项。因此,若想引用名为layer1的层,应以如下语法:
IE:document.all["layer1"]或document.all.layer1
NS:document.layers["layer1"]或document.layers.layer1
2. 层的坐标和大小。在IE中,每个涉及层的外观的属性,如位置,大小,颜色等,都是层的style属性集合的以一项,如层的左上角x坐标为document.all.layer1.style.pixelLeft,y坐标为 document.all.layer1.style.pixelTop,宽度为document.all.layer1.style.pixelWidth,高度为document.all.layer1.style.pixelHeight。还有几组属性如scrollxxx,offsetxxx,clientxxx,其中xxx为Left,Top,Width,Height ,分别描述层的滚动,位移,客户区等属性,详见MSDN中关于坐标的描述。而在NS中,每个层都有一个clip属性集,x,y,width,height是这个集的集合元素。
另外,IE中所有元素拥有同一个坐标系,无论它位于层外或层内;在NS中,每个层都有一个独立的坐标系。
3. 层的内容。IE中的层包含innerHTML和outerHTML属性(由于并非描述层的外观,所以它们不是style属性集的元素,而是层的属性),其含义如下:
innerHTML:层中的HTML代码,但是不包括层的定义。
outerHTML:层中的HTML代码,且包括层的定义。
改变这些属性值就可以改变层的内容,如下语句改变层layer1的内容为加粗的字符串"layer1":document.all.layer1.innerHTML=”<b>layer1</b>” ,而在NS中,每一个document.layers集合中的元素,即一个层,都NS被视为一个独立的窗口,有独立document属性,就象Javascript中的document属性一样,通过调用document.write函数,可以动态改变层的内容。上例在NS中应修改为:
document.layers.layer1.document.open();
doucment.layers.layer1.write("<div><b>layer1</b></div>");
document.layers.layer1.document.close;
同样,对于层中的其它可编程元素,例如图象,其引用语法如下:document.layers.layer1.document.images[imgname],而如果该图象位于层的外面,其语法应为document.images[imgname],而在IE中,无论图象位于层内或层外,其语法都是后者。
Javascript是Netscape公司首先提出的一种客户端编程的脚本语言,随后有扩展到服务器端。它的语法和概念都类似于C++,但是没有C++那样严格。IE同样支持客户端Javascript(微软还推出了类似的,功能更强大的Vbscript,但是NS却不支持)。两种浏览器对Javascript的基本实现是一样的,但是又都对它做了许多不同的扩展,而在DHTML编程中,很多情况下都需要用到这些扩展。由于此时已经没有标准可遵循,二者已经看不出有相同之处。例如,浏览器的客户区的宽度,在IE中是document.body.clientWidth,在NS中是window.innerWidth;再比如你想知道用户按浏览器的滚动条滚动了多少像素,在IE中是document.body.scrollTop,在NS中是window.pageYOffset。在这种情况下,你只能查阅二者的文档。IE的Javascript文档包含在MSDN中,也可以到微软的站点上单独下载。NS的Javascript文档可以到 http://developer.netscape.com上下载,那里也能得到NS的DHTML文档。
NS没有实现的功能。
1.IE中,页面中的任何元素都是可编程的,只要赋予它ID属性,其语法如下:
<div id=itemid>content</div>或<span id=itemid>content</span>
而在NS中,除非元素位于层中,否则无法对它编程。
2.IE中增添了元素的渐变(Transition)和滤镜(Filter)效果,NS中没有。
3.IE中支持客户端的数据绑定(Data bind),即页面中的某个元素(例如表格中的一个格)可以与服务器端的数据库的某个字段绑定,在数据内容不变的情况下,可以不必再次访问数据库而改变页面的形式(例如按某个字段重新排序)。NS同样没有实现这种特性。
以上列举了二者的如此之多的差别,那我们如何编写跨浏览器的DHTML页面呢?一种方法是编写两个独立的页面,而在入口文件中根据浏览器的不同而重定向到不同的页面,如:
<HTML><BODY>
<Script Language="Javascript">
isNS=(navigator.appName=="Netscape");
if (isNS)
window.location="ns.html";
else
window.location="ie.html";
</Script>
</BODY></HTML>
这种方法简单,页面整洁,缺点是有很大冗余,毕竟一个页面中程序是少量的,大部分静态内容在两个浏览器中并没有区别,一旦静态的内容发生改变必须在两个页面中一起更改,而且当包含DHTML的页面增多时,每一个页面都需要三个页面来实现,增大了维护的负担。
另一种方法是在同一个页面中集成两个浏览器的代码。在每一个实现特定功能的函数中都根据浏览器的不同分别写代码,如:
<HTML><BODY>
<Script Language="Javascript">
isNS=(navigator.appName=="Netscape");
function fun1(){
if (isNS)
//NS codes here
else
//IE codes here
}
</Script>
</BODY></HTML>
对于HTML代码也不同的部分,可以利用Javascript函数 document.writeln()来实现,例如对于层的定义,可以如下实现:
<Script Language="Javascript">
if(isNS)
document.writeln("<layer id=\"layer1\" left=20 top=30 width=40 height=50 z-index=2>");
else
document.writeln("<div id=\"layer1\" style=\"position:absolute;left:20;top:30;width:40;height:50;z-index:2\">");
</Script>
Layer content here
<Script Language="Javascript">
if(isNS)
document.writeln("</layer>");
else
document.writeln("</div>");
</Script>
这种实现方法维护简单,缺点是失去了页面编辑器所见即所得的特性(因为只有到运行时才能将层的定义写入浏览器,在编辑阶段它们只是些Javascript程序),调整层的坐标和大小都比较困难。在实际编程中可以先按一种浏览器的定义写,待调整完毕后再将它转成另一种定义。但总的来说,这种办法适合对HTML标准比较熟悉的开发人员。
|