14.7 创建基于裁剪的过渡效果
如果过渡效果应用得好,就可以使用户看到自己的动作行为所产生的一系列渐变效果,从而界面也就更具魅力了。基于剪切的过渡渐变操纵的是元素的可见区域,所以可以利用这种技术产生类似于擦拭、倒塌等效果!
方 法
CSS 2中规定clip CSS属性可以应用到任何非绝对定位的对象之上,而CSS 2.1则相反,它只允许clip属性应用于绝对定位的元素之上,并且CSS 2.1是当前主流的浏览器应用的规则,所以在这里所讲到的效果只是针对于绝对定位的元素的。
这种过渡渐变可以对各种事件做出响应,包括单击、等待、移动或者敲击键盘,不过这个例子只是对单击事件做出响应:
File: clip_transitions.js (excerpt)
addLoadListener(function(){setTimeout(function(){
initTransitions();}, 0);});
function initTransitions()
{
var elements = getElementsByAttribute("class", "transition");
for (var i = 0; i < elements.length; i++)
{
attachEventListener(elements[i], "click", clickTransition, false);
}
return true;
}
function clickTransition(event)
{
if (typeof event == "undefined")
{
event = window.event;
}
var target = getEventTarget(event);
while (!/(^| )transition( |$)/.test(target.className))
{
target = target.parentNode;
}
transitionSquash(target);
return true;
}
上述代码开始时对addLoadListener的调用看起来很混乱,其实在这个调用过程中做了一定的限制,如果浏览器不能接受匿名函数作为setTimeout的参数,那么就不能运行这个脚本,也就是说在这个调用过程中排除了Mac下的IE 5。由于addLoadListener的调用限制,在Mac IE 5这种版本的浏览器中将不会调用initTansitions,在这种浏览器中此页面将变成无JavaScript功能的页面。在该方法中之所以使用函数引用来使对象动起来是因为这里需要的是一个通用的方法,需要的是可以应用在一个页面的多个元素上的方法。前面已经做了一个足球动起来的画面,那时使用的方法是兼容Mac下的IE 5的。但是那个方法需要对用到的元素进行硬编码。如果也想在Mac IE 5浏览器上实现这些过渡转变,也可以使用相同的方法来实现。
initTransitions使用了第5章中的getElementsByAttribute函数,该函数用于将一个click事件监听者绑定到具有transition class的所有元素上去,这个事件监听者执行的函数是clickTransition,该函数的主要目的是获取正确的事件目标元素,其中还借助了第13章中的自定义函数getEventTarget。之后,监听者需要确定所选的目标元素是不是真正的目标元素,这个要通过检查transition class的className来确定。确定之后,就将正确的元素引用传递给transitionSquash,然后开始过渡渐变的动作。
transitionSquash表面上是将一个对象压扁的过渡渐变,这种效果需要通过逐渐将顶部和底端的边缘进行剪切使对象的高度减小来实现,这样看起来就像是对象被压扁了一样:
function transitionSquash(target)
{
if (typeof target == "undefined" || typeof target.style =="undefined")
{
target = this;
}
var increment = 5;
var width = target.offsetWidth;
var height = target.offsetHeight;
if (target.style.clip.indexOf("rect") == −1)
{
target.style.clip = "rect(" + increment + "px," + width +
"px," + (height - increment) + "px,0)";
}
else
{
var clipDimensions = getClipDimensions(target.style.clip);
if ((clipDimensions[2] − increment) − (clipDimensions[0] +
increment) > 0)
{
target.style.clip = "rect(" + (clipDimensions[0] +
increment) + "px," + clipDimensions[1] + "px," +
(clipDimensions[2] − increment) + "px," +
clipDimensions[3] + "px)";
}
else
{
target.style.clip = "rect(" + parseInt(height / 2) + "px," +
clipDimensions[1] + "px," + parseInt(height / 2) +
"px," + clipDimensions[3] + "px)";
return true;
}
}
setTimeout(function(){transitionSquash(target)}, 50);
return true;
}
transitionSquash采取的第一个措施就是对目标对象进行检测,看其是否有clip属性。如果没有,就将对象的剪切区域设置为距离底端和顶部5 pixels之内的那部分区域。
如果剪切区域已经定义好了,也就是说前面已经做过剪切,这时只需继续按照定义好的增量对剪切区域进行剪切。为了完成上述任务,需要取得剪切区域并对其进行修改,以使动画持续进行。这里是使用getClipDimensions函数来获取剪切区域的,该函数将以标准CSS尺寸顺序,即top、right、bottom、left的顺序返回一个整数数组。
File: clip_transitions.js (excerpt)
function getClipDimensions(clipString)
{
var clipValue = clipString.replace(/rect\((.*)\)/, "$1");
if (/,/.test(clipValue))
{
var clipDimensions = clipValue.split(",");
}
else
{
var clipDimensions = clipValue.split(" ");
}
for (var i = 0; i < clipDimensions.length; i++)
{
clipDimensions[i] = parseInt(clipDimensions[i]);
}
return clipDimensions;
}
可以看到,该函数需要对clip属性的rect(top,right,bottom,left)语法进行解析,目的就是保证获取的尺寸值是个整数。大多数浏览器会将这些值用逗号隔开,但是IE能自动将逗号转化为空格,所以在决定使用哪个字符来分割字符串的问题上需要引起注意。
当定义新的剪切区域的尺寸时,transitionSquash需要核实一下是否对象的某些部位还要保持可见,如果不需要,就将剪切区域定义为0高度(某些浏览器可能会使用负的剪切区域显示对象),并且在该函数返回之前不会再次调用setTimeout,从而结束过渡转变。
转换的效果如图14.7所示。

图14.7 将对象在纵向进行压缩的过渡转变效果
讨 论
利用剪切过渡转变可以实现很多种效果,如果要创建一个新的效果,需要做的只是创建一个和clickTransition相对应的函数。
transitionCurtain和transitionSquash相似,惟一不同的是这种效果是将对象在横向上压扁。
File: clip_transitions2.js (excerpt)
function transitionCurtain(target)
{
var increment = 5;
var width = target.offsetWidth;
var height = target.offsetHeight;
if (target.style.clip.indexOf("rect") == −1)
{
target.style.clip = "rect(0," + (width - increment) + "px,"
+ height + "px," +
increment + "px)";
}
else
{
var clipDimensions = getClipDimensions(target.style.clip);
if ((clipDimensions[1] - increment) - (clipDimensions[3] + increment) > 0)
{
target.style.clip = "rect(" + clipDimensions[0] + "px," + (clipDimensions
[1]−increment) + "px," + clipDimensions[2] + "px," +
(clipDimensions[3] +
increment) + "px)";
}
else
{
target.style.clip = "rect(" + clipDimensions[0] + "px," + parseInt(width
/
2) + "px," + clipDimensions[2] + "px," + parseInt(width /
2) + "px)";
return true;
}
}
setTimeout(function(){transitionCurtain(target)}, 50);
return true;
}
这种转换效果如图14.8所示。

图14.8 将对象横向压缩的卷帘式过渡转变
同样,transitonShrink也跟上面介绍的两种效果差不多,这种效果是向左上角方向进行压缩的。这种效果的实现中没有使用增量(increament)来确定多少帧之后对象才会消失,而是使用了一个称为steps的变量:
File: clip_transitions3.js (excerpt)
function transitionShrink(target)
{
var steps = 15;
var width = target.offsetWidth;
var height = target.offsetHeight;
var widthIncrement = parseInt(width / steps);
var heightIncrement = parseInt(height / steps);
if (target.style.clip.indexOf("rect") == −1)
{
target.style.clip = "rect(0," + (width − widthIncrement) +
"px," + (height − heightIncrement) + "px,0)";
}
else
{
var clipDimensions = getClipDimensions(target.style.clip);
if ((clipDimensions[1] − widthIncrement) > 0)
{
target.style.clip = "rect(0," + (clipDimensions[1] −
widthIncrement) + "px," + (clipDimensions[2] −
heightIncrement) + "px," + "0)";
}
else
{
target.style.clip = "rect(0,0,0,0)";
return true;
}
}
setTimeout(function(){transitionShrink(target)}, 50);
return true;
}
这种效果如图14.9所示。

图14.9 将对象向左上角挤压的收缩过渡转变效果
上述这些只是利用clip属性过渡转变对象的几种方法,还有很多种其他的效果,您可以自己试试看。







