UED TEAM

我们的团队博客

登录 | RSS | 收藏本站
08-10
23

JavaScript页面元素位移动画的几种实现

作者:rukey67 日期:08-10-23 时间:2:03 下午

摘要:本文主要归纳了用JavaScript分别设置元素margin,padding,left,scrollLeft属性来实现页面元素位移动画的四种方式,对每种方式的特性有一些探讨。技术重点在于对CSS特性的掌握,强调了CSS浏览器兼容功底对前端开发人员的重要性。

网页设计开发中,我们有时会在页面上放置一些动画元素,如滚动、切换、收缩、渐隐等效果,一方面吸引用户注意,增强交互性,另一方面可以有效地运用网页空间,在有限的空间内展示更多内容。然而,这类效果往往存在一些可用性问题,用Flash或者浏览器脚本来实现这类效果决定了对客户端软件环境的依赖性,增加了运行风险;同时,动画的速度、频率以及用户的可操作性也都需要进行细致地设计才能保持良好的用户体验。本文暂且抛开对其利弊的权衡不谈,仅仅是从前端开发的角度尝试探讨一下使用JavaScript和CSS技术实现页面元素位移动画(也即是常说的滚动)的几种方式。

所谓网页动画,可以概括成元素的物理属性相对于时间发生改变。这些物理属性包括高度,宽度,位置,可见性,透明度等,每种物理属性的改变都对应一类动画,也可以将多个效果进行组合,创造出更加动感的效果。有了需要控制的物理属性,还需要某种方式能对时间量进行精确控制,JavaScript提供了两个方法来对时间进行设置,setTimeout()和setInterval(),这两个方法都能精确设置一段时间间隔后执行某段程序(具体用法可参考相关手册),并且通过递归调用的方式两者的功能可以互相模仿,在制作动画中使用任意一个都是可行的。

网页动画

本文将要探讨的位移动画仅需要对元素的位置属性进行控制,这就需要回顾一下页面布局相关的一些CSS知识。直接影响一个元素(元素是相对于页面整体而言,也可以说是标签容器)在页面中的位置的样式属性主要包括,元素自身的外边距margin,元素父级容器的内边距padding,元素的浮动方式float,元素的定位属性top/right/bottom/left。这些属性中,float的属性值是枚举类型,仅有三个给定的值可选:left/right/none,其他的属性则是数值加单位的范围值,如“12px”、“-100px”,可以有无数个取值,并且可以很方便地通过脚本程序的循环对数值部分进行递增或递减处理,这样就非常适合来实现渐变动画。另外,JavaScript也提供了两个元素属性scrollLeft/scrollTop,控制元素向左/上卷起的像素值,从而影响其内部元素的位置,也常被用来实现位移动画。

下面地址的实例分别演示了用margin,padding,left,scrollLeft四种方式实现页面元素的位移动画:

请点击:演示地址 (点开后可直接查看分析源代码)
Available for IE5.0/IE5.5/IE6/IE7/IE8 & anyother modern browsers.

JavaScript页面元素位移动画的几种实现示例

示例中用不同方式实现了相同的效果,殊途同归。通过查看源码,我们可以看出以下特点:

  1. margin,padding,left的值都是带“px”单位的字符串,在读取这类值进行数学操作的时候,需要用到函数parseInt()进行提取数值,对其数值部分进行递增或递减操作后,还需要进行一个字符串合并 int+“px”然后赋值给它的样式属性;而scrollLeft属性值是不带单位的数值,直接对它进行数学运算即可,从这点看,使用scrollLeft来进行程序处理似乎要方便。
  2. scrollTop/scrollLeft的取值是有固定范围的,最小为0,最大为子元素的高宽超出父元素高宽的像素数值,可参考https://developer.mozilla.org/en/DOM/Element.scrollLeft。也就是说,用这个属性实现的动画是有范围限制的,子元素必须填满父元素,不能运动到让父元素内部出现间隙。另外,在子元素已经小于父元素的情况下,对父元素的scrollTop/scrollLeft进行设置将无效,恒为0,这个时候就无法通过此属性改变子元素的位置实现动画效果了。
  3. padding和scrollTop/scrollLeft由于不能取负值,要实现双向动画需要进行一些变通,比如设置互为反向的padding:paddingLeft-paddingRight;scrollTop/scrollLeft没有对应的反向属性scrllBottom/scrollRight,可以通过设置起始位置再来递增/递减进行模拟。定位属性top/right/bottom/left和margin则都可以直接取负值,能很方便地实现双向移动。但元素的margin属性和padding一样,像个步履沉重的中年人,它们的实际表现通常要受到其父母兄弟子女各级元素的影响,往往还会涉及到一些元素的layout属性(啊,让人闻之色变layout!这个跟大部分(浏览器兼容问题)有关的属性,请参见这篇文章的论述:http://bbs.blueidea.com/viewthread.php?tid=2636904),因此在使用它制作动画的时候也有一些局限,需要代码编写者胆大心细,具有比较深厚的CSS浏览器兼容功底。综上,定位属性top/right/bottom/left可以说是最为灵活的实现方式。

另外,也提供一种偏门方法,可以通过设置元素的border,使其颜色为网页背景色,视觉上表现为不可见,就可以作为和margin同样的效果来使用了,这里就不写代码了。子不语怪力乱神,对于一些偏门技巧,奇巧淫技,笔者向来是不推崇的,比如一些花俏的hack技术,并不像一些人所认为的有什么很高的技术含量,了解即可,不可执迷于此以至走火入魔堕入歧途。这里扯点野棉花,讲一段看来的故事。话说西域明教圣火令上的旁门武功,可谓奇巧诡谲;少林的九阳神功,可谓武林正宗淳正至极。狭路相逢,两种武功交上手,张无忌独对明教风云三使的时候,虽然开始输于招式略占下风,然而,情急中张无忌速成圣火令武功,并以九阳神功的纯正内力御使出来,马上扭转了战局,打败了风云三使。可见,招式技巧可以速成,苦练纯正的内功才是正途。写代码也是,只有练就了扎实的基本功,才能以拙御巧,无往不胜。

在我所见过的JavaScript位移动画中,使用最多的是设置定位属性top/right/bottom/left和scrollTop/scrollLeft的方式。JavaScript框架中的位移动画效果都是通过设置定位属性来实现,因为需要良好的通用性。而大部分的前端开发者本身是程序员出身,对CSS的开发并不太熟悉,因此采用了JavaScript提供的scrollTop/scrollLeft属性来实现动画。这些方式其实也没有绝对的优劣之分,根据实际情况灵活选用即可。受到的一点启发是,良好的CSS基础对于前端开发人员来说,能够拓展一些开发思路。

以上分析了位移动画的几种基本模型,可以在此基础上进行一些算法的设计,实现无缝滚动等效果,还可以在数值递增/递减中设置加速度,设置阻尼系数,就可以做出非常灵动,仿真的动画了。总之,一通百通,万变不离其宗。

Tags: , ,

相关文章

随机文章

JavaScript页面元素位移动画的几种实现 评论 (5)

  • 胡戈戈

    以前是用绝对定位来搞这个东东的,看来还有scrollTop/scrollLef这种,不错不错

  • 菜鸟飞啊飞

    我kao,倚天屠龙记都出来了..哈哈 demo那个点击后的alert有意思..

  • showhy

    前来学习,这个效果貌似没做过

  • 11

    //改变元素父级容器内间距padding的函数
    function paddingLeftEnlarge(btn){
    if(typeof(timer02)==”number”){clearInterval(timer02)};//这行很重要,很多做动画效果都遇到越来越快的问题
    var byPadding=$(“paddingWrap”);
    var paddingText=$(“paddingInfo”);
    function enlarge(){
    var s=parseInt(byPadding.style.paddingLeft)||0;
    s+=2;
    byPadding.style.paddingLeft=s+”px”;
    paddingText.innerHTML=”红色容器paddingLeft:”+byPadding.style.paddingLeft;
    if(s>580){
    s=0;
    clearInterval(timer02);
    paddingText.innerHTML=”动画停止”;
    byPadding.style.paddingLeft=”0″;
    btn.innerHTML=”重来”;
    };
    }
    timer02=setInterval(enlarge,10);
    btn.innerHTML=”停止”;
    btn.onclick=function(){
    clearInterval(timer02);
    this.innerHTML=”开始”;
    this.onclick=function(){paddingLeftEnlarge(btn)};//重设启动事件
    }
    }

    //改变元素定位left属性的函数
    function positionLeftEnlarge(btn){
    if(typeof(timer03)==”number”){clearInterval(timer03)};//这行很重要,很多做动画效果都遇到越来越快的问题
    var byLeft=$(“byLeft”);
    var leftText=$(“leftInfo”);
    function enlarge(){
    var s=parseInt(byLeft.style.left)||0;
    s+=2;
    byLeft.style.left=s+”px”;
    leftText.innerHTML=”蓝色容器left:”+byLeft.style.left;
    if(s>580){
    s=0;
    clearInterval(timer03);
    leftText.innerHTML=”动画停止”;
    byLeft.style.left=”0″;
    btn.innerHTML=”重来”;
    };
    }
    timer03=setInterval(enlarge,10);
    btn.innerHTML=”停止”;
    btn.onclick=function(){
    clearInterval(timer03);
    this.innerHTML=”开始”;
    this.onclick=function(){positionLeftEnlarge(btn)};//重设启动事件
    }
    }

    //改变元素scrollLeft(非CSS属性)的函数
    function scrollLeftEnlarge(btn){
    if(typeof(timer04)==”number”){clearInterval(timer04)};//这行很重要,很多做动画效果都遇到越来越快的问题
    var byScroll=$(“eg04″);
    var scrollText=$(“scrollInfo”);
    function enlarge(){
    byScroll.scrollLeft+=2;
    scrollText.innerHTML=”绿色容器scrollLeft:”+byScroll.scrollLeft;
    if(byScroll.scrollLeft>240){
    byScroll.scrollLeft=0;
    };
    }
    timer04=setInterval(enlarge,10);
    btn.innerHTML=”停止”;
    btn.onclick=function(){
    clearInterval(timer04);
    this.innerHTML=”开始”;
    this.onclick=function(){scrollLeftEnlarge(btn)};//重设启动事件
    }
    }
    =====================================
    1:if(s>580)
    2:if(byScroll.scrollLeft>240)
    这两个函数里面的580 240是根据什么计算出来的呢?谢谢

  • rukey67

    @11,这个是设计CSS的时候设定好的值
    为了演示动画效果保持代码简单没有动态地去取值

发表评论

评论只需审核一次,以后网友可以继续使用原来ID,邮箱进行回复:)