[原创]Javascript实现marquee无间隙/有间隙滚动

ChenReal

<marquee> 标签不属于W3C标准,在XHTML1.0后被废弃,仅IE5/IE6支持,FF和IE7已完全弃用。但滚动效果仍是网页常用需求,Flash通用性差,常规JS方案存在兼容性差、无法无缝滚动、内容不足时静止等问题。

为此开发了一款JS类 JsMarquee,可完全替代<marquee>,支持无缝/有间隙二维滚动,兼容主流浏览器,已在多个项目中验证可用。

资源下载与演示

核心JS代码

1. 主类定义(Marquee)

/*JS Marquee Version 1.2(Javascript实现Marquee的效果,实现无缝/有间隙的二维滚动效果)*/
/*Author : ChenReal
  Email  : chenreal@21cn.com
  Date   : 2007-10-22*/
function Marquee(MarName)
{
  this.ID = document.getElementById(MarName);
  this.Speed = 30; //数字越大速度越慢
  this.Direction = 0;//滚动方向:0代表左;1代表右;2代表上;3代表下 
  this.Width = 0;//宽度
  this.Height = 0;//高度
  this.Space = 0;//是否有间隙:0代表否;1代表是
  this.Tag = "p";//滚动内容的标签,默认是<p>,也可以是<ul>,实践证明:<p>与<ul>不能嵌套使用。其他标签暂时不推荐。
  //开始滚动  
  this.Start = function(){
    MarqueeStart(this,this.Direction,this.Width,this.Height,this.Speed,this.Space,this.Tag);
  }
  //停止滚动并释放对象
  this.End = function(){
    MarqueeEnd(this);
  }
}

2. 滚动初始化(MarqueeStart)

function MarqueeStart(Mar,Direction,Width,Height,Speed,Space,Tag){  
  var msobj;
  if(typeof(Mar) == "string"){
    msobj = new Marquee(Mar);
  }
  if(typeof(Mar) == "object"){
    msobj = Mar;
  }
  if(!msobj.ID) return;
  msobj.ID.style.width = Width + "px";
  msobj.ID.style.height = Height + "px";
  msobj.ID.style.overflow = msobj.ID.style.overflowX = msobj.ID.style.overflowY = "hidden";
  msobj.Direction = Direction;
  msobj.Width = Width;
  msobj.Height = Height;
  msobj.Speed = Speed;
  msobj.Space = Space;
  msobj.Tag = Tag;
  msobj.InnerDiv = msobj.ID.getElementsByTagName("div")[0];
  if(!msobj.InnerDiv) return;
  msobj.InnerDiv.innerHTML += msobj.InnerDiv.innerHTML;
  msobj.Inner = msobj.ID.getElementsByTagName(Tag); 
  if(!msobj.Inner) return;
  switch(Direction)
  {    
    case 2:  
        msobj.InnerDiv.style.width = Width + "px";
        msobj.Inner[0].style.width =Width + "px";
        msobj.Inner[1].style.width =Width + "px";
        if(Height>=msobj.Inner[1].offsetHeight || msobj.Space ==1){
          msobj.Inner[0].style.paddingTop = Height + "px";
          msobj.Inner[1].style.paddingTop = Height + "px";;
        }  
        break;
    case 3:
      msobj.InnerDiv.style.width = Width + "px";
      msobj.Inner[0].style.width =Width + "px";
      msobj.Inner[1].style.width =Width + "px";    
      if(Height>=msobj.Inner[1].offsetHeight || msobj.Space ==1){
        msobj.Inner[0].style.paddingBottom = Height + "px";
        msobj.Inner[1].style.paddingBottom = Height + "px";
      }
      break;
    default:    
      msobj.InnerDiv.noWrap = true;
      if(Width >= msobj.Inner[1].offsetWidth || msobj.Space ==1){
        msobj.Inner[0].style.paddingLeft = Width + "px";
        msobj.Inner[1].style.paddingLeft = Width + "px";
      }
      break;
  }
  
  msobj.ID.onmouseover = function(){
      clearInterval(msobj.TimerID);
  }
  
  msobj.ID.onmouseout = function(){
      clearInterval(msobj.TimerID);
      msobj.TimerID = funcInterval(MarqueeScroll,msobj.Speed,msobj);
  }
  msobj.TimerID = funcInterval(MarqueeScroll,msobj.Speed,msobj);  

}

3. 滚动核心逻辑(MarqueeScroll)

function MarqueeScroll(Mar){     
  switch(Mar.Direction)
  {
      case 0:  
          if(Mar.Inner[1].offsetWidth-Mar.ID.scrollLeft<=0)
           Mar.ID.scrollLeft-=Mar.Inner[0].offsetWidth;
          else{              
           Mar.ID.scrollLeft++;
          }
      break;
      case 1:          
          if(Mar.ID.scrollLeft==0)
           Mar.ID.scrollLeft=Mar.Inner[1].offsetWidth;
          else{
           Mar.ID.scrollLeft--;
          }          
      break;
      case 2:    
          if(Mar.Inner[1].offsetHeight-Mar.ID.scrollTop<=0)
           Mar.ID.scrollTop-=Mar.Inner[0].offsetHeight;
          else{
           Mar.ID.scrollTop++;
          }
      break;
      case 3:          
          if(Mar.ID.scrollTop<=0)
           Mar.ID.scrollTop = Mar.Inner[1].offsetHeight;
          else{
           Mar.ID.scrollTop--;
          }        
      break;
  }
}

4. 停止滚动(MarqueeEnd)

function MarqueeEnd(Mar){
  if(!Mar)return;
  if(typeof(Mar.TimerID) == "number") {
    clearInterval(Mar.TimerID);
    Mar = null;
  }
}

5. 定时器封装(funcInterval)

function funcInterval(funcName,time){
  var args=[];
  for(var i=2;i<arguments.length;i++){
      args.push(arguments[i]);
  }
  return window.setInterval(function(){
            funcName.apply(this,args);
        },time);
}

HTML使用示例

<!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=gb2312" />
<script src="js/marquee.js" language="javascript" type="text/javascript"></script>
<script language="javascript">
window.onload = function(){
  var mar = new Marquee("marquee");
  mar.Direction = 0;
  mar.Width = 270;
  mar.Height = 16;
  mar.Speed = 20;
  mar.Space = 0;
  mar.Start();

  MarqueeStart("marquee1",1,70,16,30,0,"p");
  MarqueeStart("marquee2",2,150,100,30,1,"p");
  MarqueeStart("marquee3",3,20,62,30,0,"p");

  MarqueeStart("marquee4",0,70,50,30,0,"ul");

}
</script>
<style>
.marquee {border:1px solid #999999;}
.marquee div{width:1000%;}
.marquee div p{display:block; float:left; margin:0px;}
.marquee div ul{display:block; float:left; margin:0px;padding:0px;}
.marquee div ul li{float:left; display:block; border:solid 1px #666666; padding:14px 21px 14px 21px; margin:1px 10px 1px 10px; list-style:none;}
</style>
<title>Marquee Test</title>
</head>
<body>

<div id="marquee" class="marquee">
  <div>
  <p>横向有间隙从左到右滚动</p>
  </div>
</div>

<div id="marquee1" class="marquee">
  <div>
  <p>间无向横 ~~~~~动滚左到右从隙</p>
  </div>
</div>

<div id="marquee2" class="marquee">
  <div>
  <p>从上到下<br>有间隙滚动</p>
  </div>
</div>

<div id="marquee3" class="marquee">
  <div>
  <p>从<br>下<br>到<br>上<br>有<br>间<br>隙<br>滚<br>动</p>
  </div>
</div>

<div id="marquee4" class="marquee">
  <div>
      <ul>
        <li>a</li>
        <li>b</li>
        <li>c</li>
      </ul>
  </div>
</div>
</body>
</html>

核心参数说明

参数类型说明
Direction数字滚动方向:0=左、1=右、2=上、3=下
Speed数字滚动速度,数值越大速度越慢(默认30)
Width/Height数字滚动容器的宽/高(单位:px)
Space数字是否有间隙:0=无缝滚动、1=有间隙滚动
Tag字符串滚动内容的标签,仅支持p/ul(不可嵌套使用)

核心方法

方法说明
Start()启动滚动
End()停止滚动并释放对象

特性

  1. 兼容主流浏览器(替代废弃的<marquee>);
  2. 支持横向/纵向滚动,无缝/有间隙模式自由切换;
  3. 内容长度不足时仍可正常滚动,无静止问题;
  4. 鼠标悬停时停止滚动,离开后恢复;
  5. 支持p/ul标签承载滚动内容,适配不同布局场景。