首页 > 开发 > 综合 > 正文

图片不间断滚动的特效代码详细讲解

2024-07-21 02:04:26
字体:
来源:转载
供稿:网友

我很久前在yahoo上扣的代码,兼容性很好,在windows下的主流浏览器中可以正常运行。

演示地址:index.html

代码下载:scrollpic.rar

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

scrollver.js

scrollvertical.prototype.scrollarea=null;      // 滚动的区域
scrollvertical.prototype.scrollmsg=null;       // 要滚动的内容
scrollvertical.prototype.unitheight=0;         // 单独一行滚动内容的高度(程序中通过过的要滚动行的一个节点的offsetheight获得)
scrollvertical.prototype.msgheight=0;          // 整个滚动内容的高度
scrollvertical.prototype.copymsg=null;         // 复制滚动内容(程序中使用复制scrollmsg.innerhtml来获得的)
scrollvertical.prototype.scrollvalue=0;        // 滚动的值
scrollvertical.prototype.scrollheight=0;       // 滚动高度
scrollvertical.prototype.isstop=true;          // 停止滚动
scrollvertical.prototype.ispause=false;        // 暂停滚动
scrollvertical.prototype.scrolltimer=null;     // 滚动计时器
scrollvertical.prototype.speed=2000;           // (默认)滚动的时间间隔2秒
/**
* @method ismoz - 判断是否为mozilla系列浏览器
*/
scrollvertical.prototype.ismoz = function(){
    return navigator.useragent.tolowercase().indexof('gecko') > 0;
};
/**
* @method play - 滚动信息的处理方法(函数)
* @param {object} o - 滚动类
*/
scrollvertical.prototype.play = function(o){
    var s_msg = o.scrollmsg;
    var c_msg = o.copymsg;
    var s_area = o.scrollarea;
    var msg_h = o.msgheight;
   
    var anim = function(){
        // 如果已经开始计时(间隔时间执行向上滚动),
        // 就停止它(以免无限制执行,耗系统资源)。
        if (o.scrolltimer) {
            cleartimeout(o.scrolltimer);
        }
        // 如果暂停了滚动(鼠标放到了滚动层上)
        // 开始以10毫秒的时间间隔运行滚动   
        if (o.ispause) {
            o.scrolltimer = settimeout(anim, 10);
            return;
        }
        // 当显示完所有信息后(这时滚动的距离就等于要滚动信息的高度msg_h)
        // 这时又重新开始滚动,将滚动距离清零
        if (msg_h - o.scrollvalue <= 0) {
            o.scrollvalue = 0;
        }
        else {
            o.scrollvalue += 1;
            o.scrollheight += 1;
        }
        // 根据浏览器的不同,处理滚动
        if (o.ismoz) { // mozilla引擎浏览器
            s_area.scrolltop = o.scrollvalue;
        }
        else { // 其余的浏览器则使用控制css样式处理滚动
            s_msg.style.top = -1 * o.scrollvalue + "px";
            c_msg.style.top = (msg_h - o.scrollvalue) + "px";
        }
        // 滚动高度等于显示滚动区域高度时(滚动完一行,一行内容全部显示)
        // 暂停4秒中,然后再开始执行下依次滚动。
        if (o.scrollheight % s_area.offsetheight == 0) {
            o.scrolltimer = settimeout(anim, o.speed);
        }
        else {
            // 在两行内容之间过度滚动时,每10豪秒上升1px
            o.scrolltimer = settimeout(anim, 10);
        }
    };
    // 执行滚动
    anim();
};
/**
* scrollvertical 垂直滚动的构造函数
* @param {object} disp   -  必须  显示滚动区域的dom节点(或节点id)
* @param {object} msg    -  必须  被显示的信息的dom节点(或节点id)
* @param {string} tg     -  可选  以什么标记为一行的标签名称(tagname)
*/
function scrollvertical(disp, msg, tg){
    // 给在之前定义的this.scrollarea付值
    if (typeof(disp) == 'string') {
        // 如果disp给的是节点的id,通过document.getelementbyid获取该节点
        // 然后付值给this.scrollarea
        this.scrollarea = document.getelementbyid(disp);
    }
    else {
        // 如果是dom节点,直接付给this.scrollarea
        this.scrollarea = disp;
    }
    // 以给this.scrollarea相同的方法给this.scrollmsg付值
    if (typeof(msg) == 'string') {
        this.scrollmsg = document.getelementbyid(msg);
    }
    else {
        this.scrollmsg = msg;
    }
   
    // 为了开发方便,
    // 不用一直写this.scrollmsg这么常的名字,
    // 将两个对象付给局部变量
    var s_msg = this.scrollmsg;
    var s_area = this.scrollarea;
   
    // 如果没有给定一行的识别标签,
    // 默认将li标签认为是一行的标签
    // 所以上面介绍的,tag参数是可选的
    if (!tg) {
        var tg = 'li';
    }
   
    // 获取单行的高度
    // 获取到第一(s_msg.getelementsbytagname(tg)[0])tg(一行的标签)的高度,作为单行的高度
    this.unitheight = s_msg.getelementsbytagname(tg)[0].offsetheight;
    // 获取整个信息框的高度
    // 公式为 单行高度(unitheight)*行数(s_msg.getelementsbytagname(tg).length,显示信息中包含多少个tg(行)标签)
    this.msgheight = this.unitheight * s_msg.getelementsbytagname(tg).length;
    /*
     * 复制要显示的信息:
     * 连续滚动的实现其实就是通过复制信息,
     * 并将复制的信添加到原始信息后
     * 当原始信息滚动显示完成,就接着滚动显示复制的信息
     * 但给人的错觉是,我们看到信息连续不断的显示
     */
    // 创建复制内容节点
    var copydiv = document.createelement('div');
    // 这个地方感觉有点嵌妥
    // 直接使用element.id的方式,不过看上去,主流的浏览器都支持
    // 标准的dom core方法:
    // copydiv.setattribute('id',s_area.id + "_copymsgid")
    copydiv.id = s_area.id + "_copymsgid";
    // 复制原始的信息
    // 将原始的信息s_msg中的内容,直接用innerhtml写到
    copydiv.innerhtml = s_msg.innerhtml;
    // 设置复制信息节点的高度
    copydiv.style.height = this.msgheight + "px";
    // 将复制节点添加到原始接点(scrollmsg)后
    // 其实实现的方法就是将复制信息节点(copydiv)添家到显示区域的节点(scrollarea)中
    s_area.appendchild(copydiv);
   
    this.copymsg = copydiv;
    // 开始执行滚动方法
    this.play(this);
}

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

|||

settimeout(func,time)

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

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

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

不如本例中的

settimeout(anim, o.speed);

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

function dosomething(){
    // do something
}
settimeoout('dosomething',1000);

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

function whatwedonow(){
    var str = 'this is what we do now';
    if(doalert) {
       cleartimeout(doalert)
    }  
    var doalert = settimeout(function(){
       alert(str);
    },1000);
}

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

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

cleartimeout(itimeoutid)

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

cleartimeout(o.scrolltimer);

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

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

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

function whatwedonow(){
    var str = 'this is what we do now';
    if(doalert) {
       cleartimeout(doalert); // clear
    }  
    var doalert = settimeout(function(){
       alert(str);
    },1000);
}
if (o.scrolltimer) {
    cleartimeout(o.scrolltimer); // clear
}

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

if (o.scrolltimer) {
    cleartimeout(o.scrolltimer); // clear
}
....
....
if (o.scrollheight % s_area.offsetheight == 0) {
    o.scrolltimer = settimeout(anim, o.speed);
}
else {
    o.scrolltimer = settimeout(anim, 10);
}

逻辑就是:

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

|||

介绍了大半天的settimeout和cleartimeout,呵呵,现在可以看看怎么使用这个特效吧,页面代码:

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>滚动图片</title>
<style type="text/css">
<!--
*{
    margin:0;
    padding:0;
}
body{
    text-align:center;
    background-color:#fff;
    color:#000;
    font:'宋体',sans-serif;
}
img{
    border:0;
}
ul,li{
    list-style-type:none;
}
a:link,
a:visited{
    color:#000;
    text-decoration:none;
}
a:hover{
    color:#f00;
    text-decoration:none;
}
#container{
    margin:0 auto;
    position:relative;
    margin-top:10px;
    width:720px;
    height:100px;
    overflow:hidden;
}
#message,
#message_copymsgid{
    margin:0;
    width:720px;
    overflow:hidden;
}
#container ul{
    float:left;
    width:720px;
    height:100px;
    overflow:hidden;
    clear:both;
}
#container li{
    float:left;
    text-align:center;
    width:120px;
    height:100px;
    line-height:100px;
    overflow:hidden;
    padding:0;
}
#container li img{
    width:96px;
    height:96px;
    margin-bottom:10px;
    padding:1px;
    border:1px solid #999;
}
-->
</style>
</head>
<body>
<div id="container">
<div id="message">
<ul><li><a href="http://www.yaohaixiao.com/" target="_blank" title="听海"><img src="img/img1.gif" alt="听海" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="听海"><img src="img/img1.gif" alt="听海" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="听海"><img src="img/img1.gif" alt="听海" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="听海"><img src="img/img1.gif" alt="听海" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="听海"><img src="img/img1.gif" alt="听海" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="听海"><img src="img/img1.gif" alt="听海" /></a></li>
</ul>
<ul>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="宝贝"><img src="img/img2.gif" alt="宝贝" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="宝贝"><img src="img/img2.gif" alt="宝贝" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="宝贝"><img src="img/img2.gif" alt="宝贝" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="宝贝"><img src="img/img2.gif" alt="宝贝" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="宝贝"><img src="img/img2.gif" alt="宝贝" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="宝贝"><img src="img/img2.gif" alt="宝贝" /></a></li>
</ul>
<ul>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="因为你"><img src="img/img3.gif" alt="因为你" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="因为你"><img src="img/img3.gif" alt="因为你" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="因为你"><img src="img/img3.gif" alt="因为你" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="因为你"><img src="img/img3.gif" alt="因为你" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="因为你"><img src="img/img3.gif" alt="因为你" /></a></li>
<li><a href="http://www.yaohaixiao.com/" target="_blank" title="因为你"><img src="img/img3.gif" alt="因为你" /></a></li>
</ul>
</div>
</div>
<script type="text/javascript" language="javascript" src="js/event.js"></script>
<script type="text/javascript" language="javascript" src="js/scrollver.js"></script>
<script type="text/javascript" language="javascript">
<!--
function init_scroll(){
     // 创建一个垂直滚动对象的实例
     // 显示容器为container,你也可以直接写document.getelement('container')
     var scrollpics = new scrollvertical('container','message','ul');
         scrollpics.speed = 4000;     // 间隔时间,更准确的说,是滚动完一行,停留的时间
         scrollpics.ispause = true;   // 是否暂停为true,不能一开始就滚动,需要先停留下,然后再滚动
    
     // 这个则是指定,第一次显示滚动内容第一行停留的时间为2秒
     // 2秒后ispause为false,也就不暂停滚动,开始滚动了。
     // 这个时间大家可以自己设定
     var timer_start = settimeout(function(){cleartimeout(timer_start);scrollpics.ispause = false;},2000);
     event.addevent(scrollpics.scrollarea,"mouseover",function(){scrollpics.ispause = true;});
     event.addevent(scrollpics.scrollarea,"mouseout",function(){scrollpics.ispause = false;});
}
/*
* 其实这里也可以直接写init_scroll();
* 应为我已经把脚本放到文档的最后面,
* 在加载脚本之前,所有的dom节点已经加载完毕
* 已经可以直接用脚本访问dom节点了
*/
event.addevent(window,'load',init_scroll);
//-->
</script>
</body>
</html>

刚才给大家介绍了js的一些知识点,现在就讲下相关的css技巧。

#container{
    margin:0 auto;
    margin-top:10px;
    width:720px;
    height:100px;
    overflow:hidden;
}

一定要“overflow:hidden;”,为什么?呵呵,看看我们把高度设置为了height:100px;,正好是只一行信息的高度,如果你不overflow:hidden,在firefox也许没有问题,它会严格按照你指定的高度显示相应高度的内容,而隐藏多余的部分(多余的5行),而在ie中,一直就自做聪明把容器挤高,让它把里面的全部内容都显示出来。而我们的效果也是只显示一行,而隐藏多余的5行。

|||

你可能要问了,怎么有多余的5行?呵呵,其实代码中已经解释了:

// 创建复制内容节点
    var copydiv = document.createelement('div');
    // 这个地方感觉有点嵌妥
    // 直接使用element.id的方式,不过看上去,主流的浏览器都支持
    // 标准的dom core方法:
    // copydiv.setattribute('id',s_area.id + "_copymsgid")
    copydiv.id = s_area.id + "_copymsgid";
    // 复制原始的信息
    // 将原始的信息s_msg中的内容,直接用innerhtml写到
    copydiv.innerhtml = s_msg.innerhtml;
    // 设置复制信息节点的高度
    copydiv.style.height = this.msgheight + "px";
    // 将复制节点添加到原始接点(scrollmsg)后
    // 其实实现的方法就是将复制信息节点(copydiv)添家到显示区域的节点(scrollarea)中
    s_area.appendchild(copydiv);

因为我们又复制了一份信息,并添加到要显示滚动信息的容器中了,所以3行变6行了。

呵呵,接下的也没有什么好讲了,大家看我的注释,应该可以很清楚了。唯一要注意的一点就是这里

        // 滚动高度等于显示滚动区域高度时(滚动完一行,一行内容全部显示)
        // 暂停4秒中,然后再开始执行下依次滚动。
        if (o.scrollheight % s_area.offsetheight == 0) {
            o.scrolltimer = settimeout(anim, o.speed);
        }
        else {
            // 在两行内容之间过度滚动时,每10豪秒上升1px
            o.scrolltimer = settimeout(anim, 10);
        }

o.scrollheight % s_area.offsetheight == 0,要明白它确切的意思。

#container{
    margin:0 auto;
    margin-top:10px;
    width:720px;
    height:100px;
    overflow:hidden;
}
#message,
#message_copymsgid{
    margin:0;
    width:720px;
    overflow:hidden;
}
#container ul{
    float:left;
    width:720px;
    height:100px;
    overflow:hidden;
    clear:both;
}

ul也就是我们一行的高度为100px,o.scrollheight已经滚动的高度。呵呵,不知道你发现了问题没有?

对了,问题就在 % s_area.offsetheight,我之所以没有更正原程序里的这个缺点,是因为如果你不对#container做任何修饰,这么写没有错。因为s_area也就是#container这里我只定义了height:100px;,如果我要是这么写:

#container{
    margin:0 auto;
    margin-top:10px;
    width:720px;
    height:100px;
    overflow:hidden;
    border:1px;
    padding:1px;
}

呵呵,你觉得会有什么结果?这里我就卖个官子,给大家出个作业,看看像我这样做了会,有一个什么结果,还有o.scrollheight % s_area.offsetheight == 0要怎么改该呢?

好了,特效讲解完毕,也不知道我这么讲解一个特效,对你有没有帮助。像里面的ceateelement,appendchild等等dom的方法,大家还是需要不断的学习,可能才能完全明白和掌握,我这里不可能一一都讲清楚。好了,收工!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表