杨庆虎
(贵州城市职业学院,贵州 贵阳 550025)
Web 程序设计、移动应用开发,都需要良好的UI界面和有趣的交互。运动不仅能有效地突出重点、吸引客户的眼球,还能增加系统的趣味性,实现静止对象无法实现的功能。如何让图片、对话框、导航条、留言面板等网页元素根据需要实现特定的运动特效成为系统UI设计师关注和研究的重点。解决JavaScript对象运动问题最简单和有效的方法就是采用运动框架。框架的概念最早起源于Smalltalk 环境,其中最著名的框架是Smalltalk-80 的用户界面框架MVC(Model-View-Controller),即将对象、属性、目标等参数封装到一个函数中,使用时调用函数即可,被封装好的函数即称为框架。
基础运动是高级运动研究的基础,所有JavaScript运动都包括运动驱动事件、运动方式、运动速度等。运动驱动事件是驱使运动的触发事件,如页面装载、鼠标移入移出、鼠标点击等。运动方式主要是对象运动前后属性的变化,如实现位置改变的左右移动、上下移动,实现特定属性如透明度变化等。运动速度主要由定时器和预设速度决定。
构建运动框架要注意两点:首先,在开启运动前要关闭已有定时器;其次,在运动框架中要将运动和停止使用if…else…语句隔离开,不能搅和在一起,否则会出现预想不到的Bug。下面以常见的侧边栏分享为例进行说明。侧边栏由div1 和span 标签组成,侧边栏分享JS代码如下:
上述代码定时器关闭条件为Math.abc(oDiv.offsetLeft-iTarget) 在实际项目开发中,匀速运动的情况比较少见,更多的是缓冲运动,如JavaScript 中的手风琴效果等。缓冲运动实现的原理是运动对象离目标值越大运动速度越快,反之则越慢,速度的快慢由距离的远近决定,用iSpeed 表示对象速度,iTarget 表示目标值,offsetValue表示当前值,m表示速度系数,则缓冲运动的速度公式可表示为:iSpeed=(iTarget-offsetValue)/m。 例如需要移动的对象为div1,设计div1 的初始水平位置为0,通过分析知,div1 缓冲运动的速度在不断减小,当值减小至计算机内存无法精确表示时,此时一直以这个速度循环运行,但对象无法移动,且对象位置停留在较近的某一点但没有到达目标点。经分析知引发此问题的原因是“ iSpeed=(iTarget-oDiv.offsetLeft)/m;”。因此,需要对程序进行改进,为了保证对象向左移动或向右移动均有效,引入JavaScript中的取整函数,当速度大于零向左移动时向上取整,即使用cell函数,当速度小于零向右移动时向下取整,即使用floor 函数,因此在速度语句下面增加速度取整语句:iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);同时,由于取整的实现,对象运动速度最后必为1,随着时间的推移,运动物体必将到达目标点,因此可将oDiv.offsetLeft>=iTarget 中的判定条件修改为“==”即可。经实验运动对象能实现缓冲效果并到达目标点。 如图1 所示,设可视窗口顶部隐藏区域的高度为scrollTop,窗口可视区域高度为clientHight,侧边栏高度为offsetHeight,当div 对象垂直居中时不难算出侧边栏的顶部距离Top,其计算公式为,Top=scroppTop+(clientHeight-offsetHeight)/2。采用水平缓冲运动原理,可以实现对象div的垂直居中效果。 图1 侧边样垂直居中示意图 浏览器兼容问题一直是JavaScript设计的难题,窗口隐藏区域高度取值(scrollTop),就存在浏览器兼容Bug,此处通过或运算给予解决,解决的代码为“scrollTop=document.documentElement.scrollTop||document.body.scrollTop;”。另外,通过测试,发现div1 对象到达目标后有轻微的抖动,经检查发现t 值为小数造成,因此,对目标值t采用parseInt(t)取整即可解决Bug。 多物体运动要解决抢占定时器问题,必须为每个运动对象定义独立定时器,同时,不仅要弄清楚运动目标点是哪里,还要弄清楚运动的对象是什么。例如,下列代码实现了一组div 宽度随着鼠标移入变宽,移出变窄的运动效果。 在多物体运动中,运动对象是多个,因此不能再使用document.getElementById()方法来获取对象,而是要通过诸如getElementsByTagName()、document.getElementsByClassName()等方式获取。上述代码中“oDiv[i].timer=null;”为每个div 设置独立的定时器,避免了抢占定时器问题,在对象传参过程中不仅传递了目标值iTarget,而且还明确了运动对象obj。 在多物体运动中所有的属性和变量必须独占,不能共用。例如,对多个div 进行透明度的运动,此时,必须为每个对象单独定义透明度存储对象,如果共享则可能会出现对象A 要让透明度增大,对象B 却要让透明度减小的矛盾。 在任意值运动框架中首先要解决offset(offsetWidth、offsetHeight)Bug 问题,offset 值不仅包括样式中对象的长(Width)、宽(Height)值,还包括了边框等值。 如上述代码随着时间的推移div 对象的宽度不断变窄,但如果给div 中的样式加上边框后,实际的运行效果则会随着时间的推移不断变宽,这与程序的初衷相悖。为什么会出现这种相悖现象?设对象的初始宽度(style.width)为100,加了1 像素的边框后,由于offset 值包括边框的宽度,因此offsetWidth 值为102,减去1 后对象宽度变为101,如此循环,不难看出对象的宽度会逐渐增大。 解决上述问题最有效的方式即获取对象的实际宽、高(width、Height)值,可封装一个函数,代码如下: 然后将对象宽度修改语句“oDiv.style.width=oDiv.offsetWidth-1+'px';”变更为oDiv.style.width=parseInt(getStyle(oDiv,'width'))-1+'px';即可。 任意对象任意值的运动框架代码如下: 可将上述代码封装到js文件中(如MoveFrame.js)供其他运动场景使用。 使用封装好的startMove(obj,attr,iTarget)运动框架解决系统开发中的flash运动效果如图2所示。 图2 运动框架效果图 ⑴鼠标移入浏览窗口左或右边,以淡入淡出显示左或右导航箭头,并且可以点击箭头实现图片换页。 ⑵大图换页方式为从上向下拉,对应缩略图透明度增加至100%,且位于缩略图中间。 ⑶点击缩略图,缩略图透明度增加至100%,且游览窗口显示对应大图。 ⑴采用CSS样式为页面布局,布局效果如图1。 ⑵引入封装好的运动框架js文件。 ⑶代码实现。 在代码实现中可以通过语句“aEle=document.getElementsByTagName('*');”选出样式中的所有元素。语句“if(this.index==iNow)return;”避免重复点击激发运动效果。由于主窗口图层堆叠在一起,前面的图层挡住了后面的图层,因此,必须借助语句“aBigLi[iNow].style.zIndex=iMinZindex++;”将当前图层移至顶层,这样才能使用户看到图片向下拉伸的运动效果。设有m 张缩略图,点击首张和最后一张缩略图时,其位置不变,即为0 和-(m-2)*li.width,点击其余图片时移动至中间,因此,其位置变化为-(m-1)*li.width,即使用if(iNow==0){…}else if(iNow==aSmallLi.length-1){…}else{…}语句控制。tab()函数实现了缩略图与大图运动的关联,后续程序中多次用到,因此进行了封装。 上述程序应用运动框架封装实现了浏览窗口导航箭头换页,大图、小图运动效果等,程序简洁,易读性好,代码利用率高。运动框架功能强大,不仅可以较好的完成上述运动效果,还可以用该框架完成诸如自动播放、增加图片说明等运动事件处理。 运动框架是构建系统运动的主要方式之一,应用好运动框架不仅能高效地实现运动效果,使程序简洁、易读、提高代码复用率,而且还能减少程序维护工作量,提高系统维护效率。本文从前端运动设计驱动事件、运动方式、运动速度等基础进行分析,对单物体匀速运动、水平缓冲运动、侧边栏缓冲居中的特点进行研究,并基于单物体运动的基础构建了多物体任意值运动框架,解决了系统中任意对象、任意属性、任意值的运动设计。设计的案例可以应用于系统开发中,也可以做为教学实践案例。在系统的实际应用中可以基于JSON数据对框架改进和应用,实现完美运动框架。2.2 水平缓冲运动
2.3 侧边栏缓冲居中
3 多物体运动框架
3.1 多物体单属性运动框架
3.2 多物体任意值运动框架
4 运动框架使用案例
4.1 使用案例场景说明
4.2 实现说明
5 总结