Ruby's Louvre

每天学习一点点算法

导航

javascript无缝滚动

无缝滚动好像是互联网广告最大的一个载体,可以用“无处不在”来形容它。不过它比起早期的闪光字体,浮动广告算进步了。由于需求巨大,做前台迟早会遇到它。我先给出结构层部分,再慢慢讲解其实现原理。

<dl id="marquee">
  <dt>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s017.jpg" alt="无缝滚动"/>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s018.jpg" alt="无缝滚动"/>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s019.jpg" alt="无缝滚动"/>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s020.jpg" alt="无缝滚动"/>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s021.jpg" alt="无缝滚动"/>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s022.jpg" alt="无缝滚动"/>
    <img src="http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_s023.jpg" alt="无缝滚动"/>
  </dt>
  <dd></dd>
</dl>

我自认为这个结构比网上那些纯DIV的结构好许多,起码可以节省许多id与class。都不知那个傻冒最先提出“DIV+CSS”这个说法,正确的说法应该是"xhtml+CSS"。换言之,就是在宏观的布局上,用块状元素代替table,由于DIV的默认样式较少,因此比较常用,table则回归和专注于数据显示。在微观的格式化上,用CSS代替原来b、big、center、i 、s、small、 strike、tt这些单纯用于样式设置的标签,很明显CSS的能力比它们更强大。

实现原理与纯CSS相册点击锚点切换相应的图片差不多,都是利用scrollTop。过程如下,因为我们设置dl的overflow为hidden,所以其左边的滚动条就不可见了。当我们不断增加其scrollTop时,它的内容就不断往上移动,抵达到dl的可视区,把原来上面可见内容挤掉,效果有点像设置了dl的margin-top为负数。继续增加scrollTop,直到我们看到dd元素。这时,我们要看一下dt元素了,原本它为空元素,克隆了dd元素的图片,其实是为了起一个遮眼法的效果。当dt元素完全被dd元素挤出dl的可视区时,我们惊讶地发现,这时dl元素可视区的样子和它最初的样式是一模一样的。dd元素拷贝dt元素的图片的作用也在于此。但继续往下走,就肯定会露馅,因为dd元素下面就没有元素了,没有图片给我们显示了。因此就在这一刻,我们把dl的元素scrollTop打回原形,重新回到dt元素图片的显示中。

那么问题是这一刻我们怎样确定呢?关键是这句“dt元素完全被dd元素挤出dl的可视区”,我们可以取dt元素的offsetHeight,这是dt元素的高加上padding与border,也可以取dd的offsetTop,这是dd元素顶部到dl元素顶部的距离。考虑到IE的怪癖模式,我决定先用offsetTop。既然要用offsetTop,我们需要指定offsetParent。不过许多教程都忘记了为dl元素设置position:relative。因为在IE6中,offsetParent直接为元素的父元素,而IE7,IE8与标准浏览器则为离它最近的被定了位的父级元素,没有则为body元素。

  #marquee {
    position:relative;
    height:300px;
    width:200px;
    overflow:hidden;
    border:10px solid #369;
  }
  #marquee img {
    display:block;
  }
  #marquee dd {
    margin:0px;
    padding:0px;
  }
  var Marquee = function(id){
    try{document.execCommand("BackgroundImageCache", false, true);}catch(e){};
    var container = document.getElementById(id),
    original = container.getElementsByTagName("dt")[0],
    clone = container.getElementsByTagName("dd")[0],
    speed = arguments[1] || 10;
    clone.innerHTML=original.innerHTML;
    var rolling = function(){
      if(container.scrollTop == clone.offsetTop){      
        container.scrollTop = 0;
      }else{
        container.scrollTop++;
      }
    }
    var timer = setInterval(rolling,speed)//设置定时器
    container.onmouseover=function() {clearInterval(timer)}//鼠标移到marquee上时,清除定时器,停止滚动
    container.onmouseout=function() {timer=setInterval(rolling,speed)}//鼠标移开时重设定时器
  }
  window.onload = function(){
    Marquee("marquee");
  }

上面的例子是向上滚动,向下滚动只不过是一开始把dl元素的scrollTop设置成dd元素的offsetTop的值,然后递减就是!

至于向左滚动就相对麻烦些。首先我们要把图片横着排列,包括dt元素里面的,还有后来克隆到dd元素的,这要求用到浮动。但这还未完,我们还要让dt元素与dd元素横着排列,于是我们就得对dl元素进行设置浮动。同时我们还得对dl元素的宽设置一个很大的值,目的是让它不换行,并且能一字排开所有图片。我设置为1000%,即浏览器的宽的十倍。对于图片,它浮动时,左右之间都存在间隙,设置margin与padding为0这样常现的方法是无法去掉它们。只好走极端了,让它们外套一个a元素,反正现实中当我们点击图片时它一定会跳转到另一个页面或页面的另一个地方,这就是用a元素来做的。由于a元素是内联元素,不存在盒子元素,它会向内收缩,把图片外面的空隙吞噬掉。最后,我们没有理由一下子显示所有图片,因此我们再在dl元素外面套一个div,在那里设置overflow与position与width等关键样式。

<div id="marquee">
  <dl>
    <dt>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s017.jpg" alt="无缝滚动"</a>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s018.jpg" alt="无缝滚动"</a>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s019.jpg" alt="无缝滚动"</a>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s020.jpg" alt="无缝滚动"</a>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s021.jpg" alt="无缝滚动"</a>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s022.jpg" alt="无缝滚动"</a>
      <a href="http://www.cnblogs.com/rubylouvre/"><img src="o_s023.jpg" alt="无缝滚动"</a>
    </dt>
    <dd></dd>
  </dl>
</div>
  #marquee {
    position:relative;
    width: 400px;
    overflow:hidden;
    border: 10px solid #B45B3E;
  }
  #marquee img {
    border:0px;
  }
  #marquee dl, #marquee dt,#marquee dd,#marquee a {
    float:left;
    margin:0;
    padding:0;
  }
  #marquee dl{
    width:1000%;
    height:150px;
  }

javascript就没多大改动,只不过将offsetTop换成offsetLeft,scrollTop换成scrollLeft。因此熟悉CSS,真是好处多多。

  var Marquee = function(id){
    try{document.execCommand("BackgroundImageCache", false, true);}catch(e){};
    var container = document.getElementById(id),
    original = container.getElementsByTagName("dt")[0],
    clone = container.getElementsByTagName("dd")[0],
    speed = arguments[1] || 10;
    clone.innerHTML=original.innerHTML;
    var rolling = function(){
      if(container.scrollLeft == clone.offsetLeft){
        container.scrollLeft = 0;
      }else{
        container.scrollLeft++;
      }
    }
    var timer = setInterval(rolling,speed)//设置定时器
    container.onmouseover=function() {clearInterval(timer)}//鼠标移到marquee上时,清除定时器,停止滚动
    container.onmouseout=function() {timer=setInterval(rolling,speed)}//鼠标移开时重设定时器
  }

向右滚动也不难,照瓢画葫芦就是!

再来一个滚动文字的,感觉这东西与tab一样,最大的优点是在有限的空间显示海量的信息。

posted on 2009-10-01 23:13  司徒正美  阅读(20870)  评论(34编辑  收藏  举报