动态HTML教程(五)

---《网猴》版权所有
现在,经过四天的动态HTML教程,你已经知道如何制作动画和用户界面。你可以定位对象,在网页中移动它们,用程序改变它们的z-index和可视性。你知道如何条件化不同的DOM和写在Microsoft和Netscape的浏览器中都可用的文档。也许你觉得用手工编码太辛苦,于是你抛弃了文本编辑器,投入所见即所得的编辑工具的怀抱。

但是不管你用哪中工具,你都会遇到一些问题。比如你想真正让导航条一直放在浏览器的右侧。或者用户访问你的站点时不停地调整浏览器的大小,于是Netscape用户会抱怨所有的样式信息突然消失(当你调整窗口尺寸时,Netscape扔掉了所有的样式信息)。或许,你在制作动画,并把所有的演员放在后台,让他们等着进入,但是有的人有一个非常大的高分辨率显示器,能看出页面边缘的演员。你在使用动态HTML时会遇到所有这些问题。教程的最后一天将涉及其中的一些问题。

CSS在定位上的缺点是它只有left和top属性,但是没有bottom或right。这就意味着你只能放一个对象在离浏览器窗口50个像素的位置,但是你不能只用CSS就能把对象放在离浏览器窗口右边50像素的地方。这个问题在CSS2中应该能得到解决,样式表的下一代specification正在出笼;在它被主流浏览器支持之前,你只好求助于JavaScript。

用JavaScript解决这个问题的最好方式是基于文档宽度的计算。两种4.0浏览器都在DOM中包含文档大小的对象。所以定位对象的方式是把窗口的宽度减去对象的宽度。

<div id="foo">
your content here
</div>
<script>
if (document.layers)
{
document.foo.left = window.innerWidth - document.foo.clip.width;
}
else if (document.all)
{
foo.style.left = document.body.offsetWidth - parseInt(foo.style.width);
}
</script>
这可以把div定位到屏幕的右边。这种技术也可以把对象定位到窗口底部。 两种浏览器都支持的屏幕对象是:

Feature Internet Explorer Netscape Navigator
height of the screen screen.height screen.height
width of the screen screen.width screen.width
color depth of the screen screen.colorDepth screen.colorDepth
height of the window document.body.offsetHeight* window.innerHeight
width of the window document.body.offsetWidth* window.innerWidth

*从技术上讲,这是文档的高度和宽度,不是窗口的,但是大多数情况下可以把它们看成一件事。

如果你用的是Netscape,在看这篇教程的时候,可能要调整浏览器窗口的大小以便达到较好的显示效果。这是可能会突然出现一个可怕的闪光,然后所有的定位信息都消失了,你的页面看起来象jodi.org。

这是Netscape 4.0的一个bug。有解决办法吗?较简单的方式是在页面上放一个提示:如果您是Netscape用户,当调整浏览器尺寸时,需要重新下载页面。

或者可以使用程序:

<script>
if (document.layers)
{
window.onResize = reloadIt;
}
function reloadIt()
{
document.location = document.location;
}
</script>
这种方法在大多数情况下管用。(但是,Netscape偶尔会进入重新下载文档的死循环。)

如果你经常访问网猴,你可能知道我们鼓吹在线文档中结构、表现和行为的分离。你保持你的HTML结构,用CSS进行布局,然后用JavaScript做一些事情。尽可能地不要把这三者混在一起。问题是,当你从文档的head部分应用样式规则到对象时,在IE中,整个规划会分离到不同部分。

<html>
<head>
<title>DOM example</title>
<style>
#foo {position: absolute; left: 10px; top: 10px}
</style>

<script>
function alertIt() {
alert(foo.style.left);
</script>

</head>
<body onload="alertIt()">
<div id="foo">This is the sample</div>
</body>
</html>
你得到一个空的对话框,是吗?

你的第一个反映可能是假定下载过程中断了。但是实际上是IE把这个整体分离。因为如果你查看文档,对象foo并没有样式在其中,虽然它有一个指向样式表的ID。所以foo的唯一属性是ID。你可以做一个实验,在foo标记中加入:

<div id="foo" bar="neat">This is the sample</div>
现在alert(foo.bar)会返回"neat"。你看出来在IE中发生什么了吗?标记中的任何属性都在DOM中作为对象的属性出现。但是如果它不在对象内,就在DOM中没有反映。这就是为什么把样式加到标记中。

为了修正这个问题,我们再一次使用JavaScript的object-as-reference能力。但是不指向HTML对象,我们
为按照ID为对象指定样式表规则。页面的结果和在你的脚本中的一致,但是不需要把样式放在标记行中。

<script>
function setup(myId)
{
if(document.layers)
{
myObj = document.layers[myID];
}
else if(document.all)
{
for (ss=0 ; ss < document.styleSheets.length; ss++)
{
for (sr=0 ; sr < document.styleSheets(ss).rules.length; sr++)
{
if (document.styleSheets(ss).rules(sr).selectorText == '#' + myId)
{
myObj = document.styleSheets(ss).rules(sr).style;
}
}
}
}
}
</script>
结果是循环经过所有的页面的样式表。如果其中一个与你的对象的ID匹配,它就作为这个对象的别名。你可以象从前一样处理,但是用的HTML代码更整洁。

在你完全掌握dHTML前,你需要了解event对象。两种4.0浏览器都包含event对象。它在事件创立时产生,如点击一个可点击的对象,移动鼠标,或聚焦到一个窗体元素上。Event对象被创建然后传递给处理事件的函数。

下面是event对象属性的描述,以及Netscape和IE处理它们的方式:

描述 Microsoft 属性 Netscape 属性
代表事件类型的字符串 type type
代表最初发送给对象事件的字符串 srcElement target
光标横坐标 x x
光标纵坐标 y y
相对于页面的横坐标 clientX pageX
相对于页面的纵坐标 clientY pageY
相对于屏幕的横坐标 screenX screenX
相对于屏幕的纵坐标 screenY screenY
键代码 keyCode which
Netscape返回键的代码,IE 返回true或false altKey
ctrlKey
shiftKey modifiers

4.0浏览器增加了一些新事件:

onDblClick 鼠标双击
onKeyDown 键被按下
onKeyPress 键被按下然后被释放
onKeyUp 键被释放
onMouseDown 鼠标被按下
onMouseMove 鼠标移动
onMouseUp 鼠标被释放
onResize 窗口被调整大小

4.0浏览器也增加了处理事件的新方法,虽然它们(Netscape和IE)的方式不同。Netscape用的是“时间捕捉”,IE用的是“事件气泡”。

事件处理对Netscape处理如mouseMove或keyPress等事件是必须的,它并不隐含指向一个标记或元素。你应该告诉客户注意这些事件,并告诉它用什么函数来处理它们。下面例子用window对象的captureEvents方法来描述正在捕捉的事件:

window.captureEvents(Event.MOUSEMOVE);
注意到在不用on作为名称一部分的情况下特定事件是如何被指向的。你只是告诉Netscape注意所有发生在窗口中的事件并捕捉它们。然后你需要告诉Netscape用这些被捕捉的时间做些什么。注意on又出现了。

window.onMouseMove = handlerFunction;
function handerFunction(yourEvent) {
alert(yourEvent.screenX);
}
这段代码是一个演示事件过程的烦人的例子。每次你移动鼠标,一个对话框会跳出来告诉你它的横坐标位置。以这种方式处理的事件传递一个指针到event对象。从这儿你可以获取必要的信息。一旦你厌倦了捕捉事件,你可以象这样释放它们:

window.releaseEvents(Event.MOUSEMOVE);
于是这种类型的事件不再被捕捉。

IE用不同的方法处理事件,叫做“事件气泡”。在这种方
法中,如果你有这样一个结构:

<body onclick="bloorf()">
<p onclick="baz()">
<em onclick="bar()">
<strong onclick="foo()">Click on me</strong>
</em>
</p>
</body>
如果你点击strong标记内的文本,它接收到一个onClick事件,然后发送onclick事件给<em>标记,处理它然后发送到<p>标记,等等,然后直到窗口。这样每个元素以自己的方式处理点击。但是如果你想停止气泡上传,可以取消气泡。

<script>
function foo()
{
doSomeThing();
this.event.cancelBubble = true;
}
</script>

所以如果你不想让某个事件传递到所有它包含的标记,可以象上面那样阻止它。

你可以看到,因为两种浏览器存在相似的事件,每一步都需要大量的条件化工作,而且没有简单的方式把它们映射到一个句法中。

虽然动态HTML背后有很多要了解的,但是你现在已经可以开始并使dHTML适应不同的浏览器。如果你想了解更多的内容,Microsoft和Netscape在它们的网站上都有扩展dHTML文档。

那么你觉得动态HTML怎样?爱它还是恨它?爱它所做的,但是在实现上的差异上又心存顾虑?事实上浏览器公司和World Wide Web Consortium已经意识到这种差异,所以将来应该有解决办法。

最后,有一项期末作业:

做一个动态HTML主页,让它运动、让它可视和隐藏、让它反应用户事件。

祝你编码和设计快乐!