这是我今天在使用 IE8、FF、Chrome 和 Safari 之后想到的问题的答案。
假设我们想要使用尽可能少的 JavaScript 且没有 jQuery 来垂直折叠和展开一个 div 元素(因此,为了简单起见,我们只讨论高度)。可能是您希望在页面上很好地显示和隐藏的内联错误消息框。消息框本身是有弹性的,你不知道它的实际尺寸。这里有两个一般性问题需要解决:
问题#1:offsetHeight、clientHeight 和scrollHeight 属性在不同浏览器中不一致是众所周知的。你不能依赖它们,特别是当 margin/padding/border 设置为 0 以外的值以及 CSS 高度不是默认值时(即实际折叠/展开元素时)。有 getComputedStyle(),但它仅在正常浏览器上可用,而在 IE 中不可用。 OTOH,IE 的 currentStyle 属性不会返回您可能期望的计算值(例如,您可能会看到“auto”作为高度值)。事实证明,没有边距/填充/边框的 offsetHeight 在所有现代浏览器上都是可靠且兼容的。
问题#2:(据我所知)对 div 元素进行动画处理的唯一方法是更改 style.height,但是,它不包括填充和边框,因此您无法将框动画化为 0 或对于具有非零填充和边框的元素,从 0 开始动画。 (最重要的是,IE 不接受 0px 作为 style.height,所以最小尺寸无论如何都是 1px)。
解决这两个问题的方法是用另一个具有默认样式的 div 包裹您的盒子,即 padding/margin/border 全部设置为 0,这是新 div 的默认样式。您想要折叠和展开的盒子应该位于内部,并且不应该有边距设置,如果需要,只能有填充和边框。这样,您将能够 (1) 通过 offsetHeight 可靠地确定弹性内盒的高度,以及 (2) 以 1 像素为单位设置外盒高度的动画。
那么,假设我们想要为其设置动画:
<div id="errmsg" style="display:none">
<div class="errmsg">
<div class="window-close" onClick="javascript:showErrMsg('', this.parentNode.parentNode)"></div>
<div id="errmsg.text"></div>
</div>
</div>
盒子一开始是看不见的。 “window-close”类是右侧有一个十字的小框,用于在单击时隐藏该框。使用空字符串调用 showErrMsg() 会折叠消息框(见下文)。
用于为该错误消息框设置动画的 JavaScript 代码如下(我还对不透明度进行动画处理,为简单起见,此处省略了该动画):
var ANIMATE_STEPS = 10;
var ANIMATE_DELAY = 20;
function _obj(obj, parent)
{
if (typeof obj == 'string')
obj = (parent ? parent : document).getElementById(obj);
return obj;
}
function _setStyleHeight(obj, h)
{
_obj(obj).style.height = Math.round(h) + 'px';
}
function _animateVertFold(obj, cur, by, lim)
{
obj = _obj(obj);
cur += by;
if (by < 0 && cur <= 1)
{
obj.style.display = 'none';
_setStyleHeight(obj, 1); // IE doesn't accept 0
}
else if (by > 0 && cur >= lim)
{
_setStyleHeight(obj, lim);
}
else
{
_setStyleHeight(obj, cur);
setTimeout('_animateVertFold(\'' + obj.id + '\', ' +
cur + ', ' + by + ', ' + lim + ')', ANIMATE_DELAY);
}
}
function _expandElem(obj)
{
obj = _obj(obj);
if (obj.style.display == 'none')
{
obj.style.overflow = 'hidden';
_setStyleHeight(obj, 1);
obj.style.display = 'block';
var innerDiv = obj.getElementsByTagName('div')[0]; // better way?
var h = innerDiv.offsetHeight;
if (h > 0)
_animateVertFold(obj, obj.offsetHeight, h / ANIMATE_STEPS, h);
}
}
function _shrinkElem(obj)
{
obj = _obj(obj);
if (!obj.style.display || obj.style.display != 'none')
{
obj.style.display = 'block';
obj.style.overflow = 'hidden';
var h = obj.offsetHeight;
_animateVertFold(obj, h, - h / ANIMATE_STEPS, h);
}
}
function showErrMsg(msg, id)
{
id || (id = '_errmsg');
obj = _obj(id);
if (msg != '')
{
_obj(id + '.text').innerHTML = msg;
_expandElem(obj);
}
else
_shrinkElem(obj);
}
您可以调用 showErrMsg(),代码将处理其余的事情。您必须将窗口关闭类定义为模仿 GUI 关闭窗口按钮的类。当然,“errmsg”类作为一个具有不同背景颜色、边框和可能字体的盒子。