嵌套层 (Nesting Layers)

我之所以把嵌套层这个话题留到现在, 是因为它在许多方面对你的脚本有重大影响.

嵌套指的是把一组层集中组合到一个统一的元素中. 换句话说, 嵌套层就是 "层中套层".

具体做法就是子层按照一定的规则放置在主层之中. 同样, 如果主层被剪切, 子层在主层中的显示则类似于层在浏览器窗口中的显示. 你将看不到移动到主层边界以外的子层部分 -- 子层的显示属性并没有改变只是它看上去就象是移出了浏览器窗口:

Nesting Diagram

我发现当你需要定位许多复杂的元素时嵌套功能会使之变得很简单. 这是因为所有的子层位置都是相对于主层的位置, 它们实际上是被"锁定"在主层中. 如果你想移动主层, 你完全不必去改变子层的位置, 因为它们会相应地随着主层而移动. 这同样适用于滑动功能 -- 所有的子层将随主层滑动而滑动.

在Netscape和Internet Explorer中用JavaScript来表现嵌套层其结果大相径庭. 我承认要用脚本语言以使嵌套层在两个浏览器中都能正常工作是件令人痛苦的事情 -- 这也是为什么你很少见到这个功能被用于网页中. 但是我已经找到了很好的办法来解决这个一直困扰着我的问题, 并且我认为嵌套功能是如此之有用以至于一旦你掌握了它便会欲罢不能.

样式单(Stylesheets)和嵌套(Nesting):

嵌套层的实质就是把子层DIV写在主层DIV之中:

<DIV ID="parent1Div">

	<DIV ID="child1Div"></DIV>
	
	<DIV ID="child2Div"></DIV>
	
</DIV>

样式(styles)无法在 DIV 标签中正常工作. 这是因为如果你用"内联(inline)"方式定义样式, 则 Netscape 将不支持嵌套层. Netscape 看上去只支持一组嵌套层, 如果你有更多, 那么 Netscap 将忽略掉后面所有层的样式. 所以我们只能用 STYLE 标签来定义样式. 本科所有相关示例都将遵循这一条.

层叠样式单(CSS)从原则上相同, 当它独立于 DIV 标签时除外:

<STYLE TYPE="text/css">
<!--
#parent1Div {position:absolute; left:100; top:80; width:230; height:120; clip:rect(0,230,120,0); background-color:#C0C0C0; layer-background-color:#C0C0C0;}
#child1Div {position:absolute; left:-20; top:40; width:70; height:70; clip:rect(0,70,70,0); background-color:#FF0000; layer-background-color:#FF0000;}
#child2Div {position:absolute; left:180; top:70; width:70; height:70; clip:rect(0,70,70,0); background-color:#0000FF; layer-background-color:#0000FF;}
-->
</STYLE>

<DIV ID="parent1Div">

	<DIV ID="child1Div"></DIV>
	
	<DIV ID="child2Div"></DIV>
	
</DIV>

点击这里看看这个示例.

我在例子中同时定义了剪切区(即可视区). 一般说来当你使用嵌套时你就应该定义剪切(clip)值并定义层的颜色.

JavaScript 和嵌套(Nesting):

运用 JavaScript 在 Netscape 和 Internet Explorer 中实现嵌套是截然不同的. 在IE中, 层是否被嵌套并没有什么区别, 你可以象以前一样来定义属性:

childLayer.style.properyName

然而在Netscape中如果你想获取一个子层的属性就必须附加主层的信息:

document.parentLayer.document.childLayer.propertyName

这里层的名字前添加了"document"是因为 Netscape 把层视为单独的文件 -- 子层是主层的一部分.

层的嵌套不论是数量还是次数都是没有限制的 -- 你只管将 DIV 一层一层地套下去. 例如我们把上面的示例改为将 child2Div 嵌套在 child1Div 中:

<DIV ID="parent1Div">

	<DIV ID="child1Div">
	
	<DIV ID="child2Div"></DIV>
	
	</DIV>
	
</DIV>

在这中情况下要获取 child2Div 的属性你就必须这样写:

document.parent1Div.document.child1Div.document.child2Div.propertyName

以上种种最后要集中到指针变量当中. 以下是我为最开始的示例定义的指针变量:

function init() {
	if (ns4) {
		parent1 = document.parent1Div
		child1 = document.parent1Div.document.child1Div
		child2 = document.parent1Div.document.child2Div
	}
	if (ie4) {
		parent1 = parent1Div.style
		child1 = child1Div.style
		child2 = child2Div.style
	}
}

下面还有一些其它问题...

重温 CSS 属性:

不幸的是我被 Internet Explorer 中一些小的技术原因困扰了很长时间. 当你用 STYLE 标签定义样式时, 在 IE 中无法读取任何属性. 所以在 IE 中如果你用parent1来查看当前位置:

alert(parent1.left)

你就会发现你将一无所获. 对于所有的 CSS 属性(left, top, width, height, visibility etc.)这都是个事实.

点击这里看看这个查看层的属性的示例. 在 Netscape 中一切正常而在 IE 中警示框内没有任何显示.

我不明白为什么微软(Microsoft)的IE浏览器会存在这个问题. 它只发生在使用 STYLE 标签的时候, 而且只针对属性的初始值. 一旦你在 JavaScript 中改变其属性则不再有任何问题.

我们应该怎么办呢? 如果我们希望象早些时候所作的那样(xpos and ypos)定义其它属性, 我们就需要另觅途径以找到层的当前定位. 幸好 Microsoft 为 IE4 提供了一些额外的非标准 CSS 属性:

这些属性不会受到 IE4 STYLE 标签的影响, 因此我们可以使用它们来获取层的当前位置. 以下是增加了 xpos 和 ypos 属性的新代码组成的指针变量:

function init() {
	if (ns4) {
		parent1 = document.parent1Div
		parent1.xpos = parent1.left
		parent1.ypos = parent1.top
		child1 = document.parent1Div.document.child1Div
		child1.xpos = child1.left
		child1.ypos = child1.top
		child2 = document.parent1Div.document.child2Div
		child2.xpos = child2.left
		child2.ypos = child2.top
	}
	if (ie4) {
		parent1 = parent1Div.style
		parent1.xpos = parent1.offsetX
		parent1.ypos = parent1.offsetY
		child1 = child1Div.style
		child1.xpos = child1.offsetX
		child1.ypos = child1.offsetY
		child2 = child2Div.style
		child2.xpos = child2.offsetX
		child2.ypos = child2.offsetY
	}
}

点击这里查看示例.

这样你就可以象前面那样改变层的位置了.

点击这里查看运用此函数来移动主层及子层的示例.

显示(Visibility)与嵌套(Nesting):

同样, 如果你使用 STYLE 标签来定义层, 那么在 IE4 中你将无法得到原始显示值. 但以我的经验来讲, 获取显示值实在没有什么必要. 通常你已经知道一个层是否显示. 受到影响的只是最初显示属性 -- 当你在 JavaScript 中改变了显示属性后你就可以找到那些值了.

嵌套层的显示与隐藏运行起来要比你想象中的好. 一旦当你定义了指针变量你就可以使用我在显示(Showing)与隐藏(Hiding)讲过的显示/隐藏函数了.

有一点我需要讲明. 如果你对子层的显示属性不加定义, 那么它将承袭主层的显示属性值. 在这种情况下如果你隐藏或显示主层, 所有的子层将随之隐藏或显示. 但是... 在 Netscape 中如果你只定义了子层的显示属性或在 JavaScript 中开始改变显示属性则会丧失隐藏或显示能力. 这种情况下, 当你隐藏主层时, 正在显示的子层将仍然显示.

为了改变这种状况, 你必须将显示属性设回"inherit"以取代"visible"(即Netscape中的"show"). 因此为了替代使用 showObj()函数, 你必须把显示属性手动设定为:

mychild.visibility = "inherit"

这样做的目的是如果主层是显示的, 子层也会是显示的, 如果主层被隐藏, 子层也将被隐藏.

首页 下一课: 键击事件
copyright 1998 Dan Steinman
Translated by Cartouche YU