不间断滚动图片Javascript特效讲解

开发 后端
本文根据一个实例来分析JavaScript特效代码。通过学习本教程,可以学会不间断滚动图片的JavaScript实现方法。

我们来分析下代码(代码中我已经写了很详细的注释),要之其所以然,在解读别人的代码中学习提高自己,然后可以灵活运用,这个才是我将这个效果贴出来的主要目的,代码如下:

scrollver.js

  1. scrollVertical.prototype.scrollArea=null;      // 滚动的区域  
  2. scrollVertical.prototype.scrollMsg=null;       // 要滚动的内容  
  3. scrollVertical.prototype.unitHeight=0;         // 单独一行滚动内容的高度(程序中通过过的要滚动行的一个节点的offsetHeight获得)   
  4. scrollVertical.prototype.msgHeight=0;          // 整个滚动内容的高度  
  5. scrollVertical.prototype.copyMsg=null;         // 复制滚动内容(程序中使用复制scrollMsg.innerHTML来获得的)  
  6. scrollVertical.prototype.scrollValue=0;        // 滚动的值  
  7. scrollVertical.prototype.scrollHeight=0;       // 滚动高度  
  8. scrollVertical.prototype.isStop=true;          // 停止滚动  
  9. scrollVertical.prototype.isPause=false;        // 暂停滚动   
  10. scrollVertical.prototype.scrollTimer=null;     // 滚动计时器  
  11. scrollVertical.prototype.speed=2000;           // (默认)滚动的时间间隔2秒  
  12. /**  
  13. * @method isMoz - 判断是否为Mozilla系列浏览器  
  14. */   
  15. scrollVertical.prototype.isMoz = function(){  
  16.     return navigator.userAgent.toLowerCase().indexOf('gecko') > 0;  
  17. };  
  18. /**  
  19. * @method play - 滚动信息的处理方法(函数)  
  20. * @param {Object} o - 滚动类  
  21. */   
  22. scrollVertical.prototype.play = function(o){  
  23.     var s_msg = o.scrollMsg;  
  24.     var c_msg = o.copyMsg;  
  25.     var s_area = o.scrollArea;  
  26.     var msg_h = o.msgHeight;  
  27.       
  28.     var anim = function(){  
  29.         // 如果已经开始计时(间隔时间执行向上滚动),  
  30.         // 就停止它(以免无限制执行,耗系统资源)。  
  31.         if (o.scrollTimer) {   
  32.             clearTimeout(o.scrollTimer);  
  33.         }  
  34.         // 如果暂停了滚动(鼠标放到了滚动层上)  
  35.         // 开始以10毫秒的时间间隔运行滚动      
  36.         if (o.isPause) {  
  37.             o.scrollTimer = setTimeout(anim, 10);  
  38.             return;  
  39.         }  
  40.         // 当显示完所有信息后(这时滚动的距离就等于要滚动信息的高度msg_h)  
  41.         // 这时又重新开始滚动,将滚动距离清零  
  42.         if (msg_h - o.scrollValue <= 0) {  
  43.             o.scrollValue = 0;  
  44.         }  
  45.         else {  
  46.             o.scrollValue += 1;  
  47.             o.scrollHeight += 1;  
  48.         }  
  49.         // 根据浏览器的不同,处理滚动  
  50.         if (o.isMoz) { // Mozilla引擎浏览器  
  51.             s_area.scrollTop = o.scrollValue;  
  52.         }  
  53.         else { // 其余的浏览器则使用控制CSS样式处理滚动  
  54.             s_msg.style.top = -1 * o.scrollValue + "px";  
  55.             c_msg.style.top = (msg_h - o.scrollValue) + "px";  
  56.         }  
  57.         // 滚动高度等于显示滚动区域高度时(滚动完一行,一行内容全部显示)  
  58.         // 暂停4秒中,然后再开始执行下依次滚动。  
  59.         if (o.scrollHeight % s_area.offsetHeight == 0) {  
  60.             o.scrollTimer = setTimeout(anim, o.speed);  
  61.         }  
  62.         else {  
  63.             // 在两行内容之间过度滚动时,每10豪秒上升1px  
  64.             o.scrollTimer = setTimeout(anim, 10);  
  65.         }  
  66.     };  
  67.     // 执行滚动  
  68.     anim();  
  69. };  
  70. /**  
  71. * scrollVertical 垂直滚动的构造函数  
  72. * @param {Object} disp   - 必须 显示滚动区域的DOM节点(或节点ID)   
  73. * @param {Object} msg    - 必须 被显示的信息的DOM节点(或节点ID)  
  74. * @param {string} tg     - 可选 以什么标记为一行的标签名称(tagName)  
  75. */ 
  76. function scrollVertical(disp, msg, tg){  
  77.     // 给在之前定义的this.scrollArea付值  
  78.     if (typeof(disp) == 'string') {  
  79.         // 如果disp给的是节点的ID,通过document.getElementById获取该节点  
  80.         // 然后付值给this.scrollArea  
  81.         this.scrollArea = document.getElementById(disp);  
  82.     }  
  83.     else {  
  84.         // 如果是DOM节点,直接付给this.scrollArea  
  85.         this.scrollArea = disp;  
  86.     }  
  87.     // 以给this.scrollArea相同的方法给this.scrollMsg付值  
  88.     if (typeof(msg) == 'string') {  
  89.         this.scrollMsg = document.getElementById(msg);  
  90.     }  
  91.     else {  
  92.         this.scrollMsg = msg;  
  93.     }  
  94.       
  95.     // 为了开发方便,  
  96.     // 不用一直写this.scrollMsg这么常的名字,  
  97.     // 将两个对象付给局部变量  
  98.     var s_msg = this.scrollMsg;  
  99.     var s_area = this.scrollArea;  
  100.       
  101.     // 如果没有给定一行的识别标签,  
  102.     // 默认将li标签认为是一行的标签  
  103.     // 所以上面介绍的,tag参数是可选的  
  104.     if (!tg) {  
  105.         var tg = 'li';  
  106.     }  
  107.       
  108.     // 获取单行的高度  
  109.     // 获取到***(s_msg.getElementsByTagName(tg)[0])tg(一行的标签)的高度,作为单行的高度  
  110.     this.unitHeight = s_msg.getElementsByTagName(tg)[0].offsetHeight;  
  111.     // 获取整个信息框的高度  
  112.     // 公式为 单行高度(unitHeight)*行数(s_msg.getElementsByTagName(tg).length,显示信息中包含多少个tg(行)标签)  
  113.     this.msgHeight = this.unitHeight * s_msg.getElementsByTagName(tg).length;  
  114.     /*   
  115.      * 复制要显示的信息:  
  116.      * 连续滚动的实现其实就是通过复制信息,  
  117.      * 并将复制的信添加到原始信息后  
  118.      * 当原始信息滚动显示完成,就接着滚动显示复制的信息  
  119.      * 但给人的错觉是,我们看到信息连续不断的显示  
  120.      */ 
  121.     // 创建复制内容节点  
  122.     var copydiv = document.createElement('div');  
  123.     // 这个地方感觉有点嵌妥  
  124.     // 直接使用element.id的方式,不过看上去,主流的浏览器都支持  
  125.     // 标准的DOM Core方法:  
  126.     // copydiv.setAttribute('id',s_area.id + "_copymsgid")  
  127.     copydiv.id = s_area.id + "_copymsgid";  
  128.     // 复制原始的信息  
  129.     // 将原始的信息s_msg中的内容,直接用innerHTML写到  
  130.     copydiv.innerHTML = s_msg.innerHTML;  
  131.     // 设置复制信息节点的高度  
  132.     copydiv.style.height = this.msgHeight + "px";  
  133.     // 将复制节点添加到原始接点(scrollMsg)后  
  134.     // 其实实现的方法就是将复制信息节点(copydiv)添家到显示区域的节点(scrollArea)中  
  135.     s_area.appendChild(copydiv);  
  136.       
  137.     this.copyMsg = copydiv;  
  138.     // 开始执行滚动方法  
  139.     this.play(this);  
  140. }  
  141.  

我在脚本的注释中已经说了这个效果的实现原理,而实现一个效果的关键就是在于运用setTimeout方法和clearTimeout方法。

setTimeout(func,time)

setTimeout是window对象的一个方法,所以如果要是看到这么写window.setTimeout你不要感到奇怪,我们平时一般都省略了window。

setTimeout方法接受两个参数:
func - 在指定时间间隔内要执行的函数;
time - 执行函数的时间间隔(以毫秒为单位,1000毫秒等于1秒)

我一开始没有解释setTimeout的功能,而是先说了两个参数的意思,我想大家看了后就会有所了解,setTimeout的功能就是:设置定时器,在一段时间之后执行指定的代码。

不如本例中的:

setTimeout(anim, o.speed);

也许你有看过类似的写法:

  1. function dosomething(){  
  2.     // do something  
  3. }  
  4. setTimeOout('dosomething',1000); 

个人建议不要这么写,是这样的代码的可读性太差,虽然也可以正常执行。相信你看到的类似的代码也是很久前的东西了。如果你还在新买的某本书中看到这样的写法,我想你可能很不幸买了本烂书。现在一般我们都这么做:

  1. function whatWeDoNow(){  
  2.     var str = 'this is what we do now';  
  3.     if(doalert) {  
  4.        clearTimeout(doalert)  
  5.     }     
  6.     var doalert = setTimeout(function(){  
  7.        alert(str);  
  8.     },1000);  

而且不知道你发现没有,这么写还有一个好处,你的function还可以接受其他的参数,比如这里我们可以接受whatWeDoNow()函数中的局部变量。如果你再结合闭包的使用,好处会更显而易见。

刚才说的一点应该说是一个不好的使用setTimeout的习惯。呵呵,接下来我还要说的一个更不好的使用习惯就是只使用setTimeout()方法,而不使用clearTimeout()方法。

clearTimeout(itimeoutid)

clearTimeout()方法的功能是停止定时器,大家看上面的代码:

clearTimeout(o.scrollTimer);

Timer(定时器),够直接吧。那么为什么要停止定时器?什么时候停止呢?

为什么要停,我想用个反问:能一直不停吗,你的机器受得了吗?这里我想应该说说我们使用setTimeout的目的,我们通常使用它来实现像本例这 样的动画效果。需要在很短的时间内连续不断的执行定时器,当然它是要占资源的啊。想想,只是不断的创建,而且往往我们做的处理,在1秒中内会执行很多次函 数,一两次还好,上百上千次,而且一个复杂些的动画,执行很短的时间内几万次也不是没有可能事情。你想想,如果我们不在每执行完一次后,销毁它。要是再加 上定时器执行的函数又是个比较NB点的运算,你的宝贵的系统资源...,呵呵!

所以应该向我给的例子中那样,记得在每次执行了定时器后停止(销毁,释放资源)它。

  1. function whatWeDoNow(){  
  2.     var str = 'this is what we do now';  
  3.     if(doalert) {  
  4.        clearTimeout(doalert); // clear  
  5.     }     
  6.     var doalert = setTimeout(function(){  
  7.        alert(str);  
  8.     },1000);  
  9. }  
  10. if (o.scrollTimer) {   
  11.     clearTimeout(o.scrollTimer); // clear  

呵呵,其实销毁的方法很简单,就是在每次创建定时器前,判断是否已经创建了订时器,就像特效例子中的

  1. if (o.scrollTimer) {   
  2.     clearTimeout(o.scrollTimer); // clear  
  3. }  
  4. ....  
  5. ....  
  6. if (o.scrollHeight % s_area.offsetHeight == 0) {  
  7.     o.scrollTimer = setTimeout(anim, o.speed);  
  8. }  
  9. else {  
  10.     o.scrollTimer = setTimeout(anim, 10);  

是不是一个很流畅的循环?现在大家应该知道了,为什么要clearTimeout和何时clearTimeout了吗?


【编辑推荐】

  1. 不唐突的JavaScript的七条准则
  2. JavaScript中的Object到底是什么
  3. JavaOne 2009第三天:微软与Sun/Oracle携手并进
  4. 开发高可移植性J2ME的软件
  5. Java虚拟机(JVM)中的内存设置详解
责任编辑:王观 来源: 动态网站制作指南
相关推荐

2016-03-27 15:06:02

Veeam/业务永续

2015-01-26 16:58:38

ISSU在线升级技术不间断网络华为

2023-10-25 08:01:30

redis主库服务

2011-06-15 11:14:58

惠普集装箱EcoPOD

2011-07-22 13:30:52

JavaScript

2021-02-22 22:06:54

软件安全数据安全漏洞

2023-08-29 17:08:14

5G物联网

2009-11-04 21:47:55

2018-08-20 15:43:51

新华三

2024-01-25 10:20:40

防火墙网络 安全双机热备

2011-09-19 13:03:02

2015-12-28 15:24:48

数据中心网络设备

2009-12-01 11:31:59

不间断电源

2011-11-10 15:14:54

华硕无线路由RT-N13U

2022-09-09 14:23:32

数据中心IT服务

2021-10-09 17:27:21

数据中心数字化转型IT

2010-05-14 16:34:59

IT管理移动通信Avocent

2012-03-15 17:46:49

BanggooADC应用交付

2010-05-14 16:54:55

校园网IT运维Avocen
点赞
收藏

51CTO技术栈公众号