首頁 > web前端 > js教程 > 主體

JavaScript實作圖片輪播元件程式碼範例

高洛峰
發布: 2016-12-05 17:14:25
原創
1292 人瀏覽過

本文介紹了JavaScript實作圖片輪播組件,廢話不多說了直接看下面:

效果:

JavaScript實作圖片輪播元件程式碼範例

自動循環播放圖片,下方有按鈕可以切換到對應圖片。

新增一個動畫來實現圖片切換。

滑鼠停在圖片上時,輪播停止,出現左右兩個箭頭,點選可以切換圖片。

滑鼠移開圖片區域時,從目前位置繼續輪播。

提供一個接口,可以設定輪播方向,是否循環,間隔時間。

對HTML、CSS的要求:

<div class="carousel-box">
  <div class="carousel">
    <ul class="clearfix" >
      <li><img src="img/carousel01.jpg" alt=""></li>
      <li><img src="img/carousel02.jpg" alt=""></li>
      <li><img src="img/carousel03.jpg" alt=""></li>
      <li><img src="img/carousel04.jpg" alt=""></li>
      <li><img src="img/carousel05.jpg" alt=""></li>
      <li><img src="img/carousel06.jpg" alt=""></li>
    </ul>
  </div>
</div>
登入後複製

必須是兩個盒子嵌套,最裡面的盒子需要有一個ul,圖片需要被包含在li裡。

可以更改類別名,同時將css檔案中的對應類別名稱替換即可。配置元件時傳入正確的DOM元素即可。

不限制圖片寬度和數量,在css檔案中更改數值即可。

/*需要更改的值*/
.carousel img{ 
  width: 600px;
  height: 400px;
}
.carousel,
.carousel-box {
  width: 600px; /*单张图片宽度*/
  height: 400px; /*单张图片高度*/
}
.carousel ul{
  width: 3600px; /*单张图片宽度x图片数量*/
}
登入後複製

原理:

將所有圖片橫向排列,最外層容器和包裹容器設定overflow:hidden。最外層容器用於按鈕和箭頭的定位。利用包裹容器的scrollLeft屬性控制顯示哪張圖片。

思路:

想要實現這些功能,應該有以下一些方法:

1.圖片切換函數。接受一個參數,表示滾動方向。呼叫緩動函數切換圖片。呼叫切換按鈕圖示函數點亮相應的按鈕。

2.緩動函數。

3.點亮按鈕函數。

4.初始化函數。用於綁定事件,建立按鈕和箭頭,初始化最初位置。

5.建立箭頭函數。

6.建立按鈕函數。

7.開始輪播函數。

8.輪播函數。

9.停止函數。用於停止輪播。

還有一些公用方法:$():選擇DOM元素。 addClass(ele,"className"):為元素新增類別名稱。 removeClass(ele,"className")移除元素的類別名稱。 $.add(ele,"type",fun):給一個DOM節點綁定事件。 getCSS(ele,"prop"):取得元素對應屬性的值。 $.delegateTag("selector","tagName","type",fun):事件代理程式。

實作:

假設有6張圖片,每張圖片寬度為600px。依照功能的獨立性來完成:

1.緩動函數  liner

緩動函數的作用是一點一點的改變目標元素的屬性值,直到達到目標值。使用它的元素可能是水平輪播的圖片,也可能是垂直輪播的圖片,也可能是想從頁面左端到達頁面右端的小盒子。所以它應該接收四個參數(目標元素,要改變的屬性值,目標值,移動次數)。

liner=function(ele,prop,next,num){
  var speed=(next-ele[prop])/num,
    i=0;
  (function(){
    ele[prop]+=speed;
    i++;
    if (i<num) {
      setTimeout(arguments.callee,30);
    }
  })();  
},
登入後複製

2.點亮按鈕函數  light

點亮按鈕本質上就是給按鈕添加一個active類,熄滅按鈕就是給按鈕移除active類。

那麼如何知道當前按鈕是哪一個呢?

最簡單的方法是直接獲取,所以可以為每個按鈕添加一個index屬性,當需要點亮按鈕時,將要點亮的按鈕的index傳給這個函數即可。

那麼如何知道要熄滅的按鈕是哪一個呢?

最簡單的方法也是直接獲取,所以可以在作用域鏈末端加上一個變數active,記住目前亮著的按鈕,這個函數直接將他熄滅就可以了。

light=function(index){
  removeClass(active,"active");
  active=$(this.wrapSelec+" "+"[index="+index+"]");
  addClass(active,"active");
}
登入後複製

3.圖片切換函數  go

需要計算出下一個scrollLeft的值:

如果是向左移動的話,scrollLeft應該-600,如果已經是0,就切換為3000.所以是ele.scrollLeft ==0?width*(len-1):ele.scrollLeft-width;

如果是向右移動的話,scrollLeft應該+600,即0——>600,600——>1200,...,3000—— >0。這裡可以像上面那樣用判斷,也可以用一個公式next=(cur+distance)%(distance*num)。即(ele.scrollLeft+width)%(width*len)

需要獲得下一個要被點亮的按鈕的index:

和計算scrollLeft的思路一樣,往左移動:index===0? len- 1:index-1; 往右移動:(index+1)%len

go=function(dire){
  var index=active.getAttribute("index")-0,
    nextIndex,
    nextPosition;
  if (dire==="next") {
    nextIndex=(index+1)%len;
    nextPosition=(ele.scrollLeft+width)%(width*len);
  }else{
    nextIndex=index===0? len-1:index-1,
    nextPosition=ele.scrollLeft===0?width*len:ele.scrollLeft-width;
  }
  light(nextIndex);
  animate.liner(ele,"scrollLeft",nextPosition);  
}
登入後複製

其中的len(圖片總數)、width(圖片寬度)、ele(包裹容器)也會被其他函數訪問,所以也添加到作用域鏈末端。

len=ele.getElementsByTagName("img").length

width=parseInt(getCSS(ele.getElementsByTagName("img")[0],"width");

=$ele(Selecele)包裹容器的selector,例如.carousel

4.建立箭頭函數createArrow

建立一個向左的箭頭,綁定事件處理函數,用於向左移動。 ,用於向右移動。 ,例如.carousel-box

5.建立按鈕函數createBtn

给每个按钮添加一个index用于点亮和熄灭,给按钮组添加一个类名用于设置样式和获取它:

createBtn=function(){
  var div=document.createElement("div"),
    btns=&#39;&#39;;
  for(var i=0;i<len;i++){
    btns+=&#39;<a href="#" index="&#39;+i+&#39;"></a>&#39;;
  }
  div.innerHTML=btns;
  addClass(div,"carousel-btn");
  container.appendChild(div);
}
登入後複製

6.轮播函数

根据要求(顺时针、逆时针)判断要调用go("prev")还是go("next")。

如果要求循环,则再次调用自己。如果不循环,则在轮播一轮后停止。

所以这里需要一个变量来判断方向,一个变量来判断是否循环,一个变量来计数。

所以又有四个变量被加到作用域链末端。direction、loop、count、begin用于清除定时器。

circle=function(){
  count++;
  if (loop||count<len) {
    if (direction==="forward") {
      go("next");
    }else{
      go("prev");
    }
  }
  begin=setTimeout(arguments.callee,t);
}
登入後複製

7.停止函数 stop

stop=function(){
  clearTimeout(begin);
}
登入後複製

8.初始化函数 init

如果是第一次使用轮播,则创建按钮和箭头,并给按钮绑定click事件处理程序(获取点击的按扭index点亮它,切换到相应图片),然后根据顺时针或逆时针来展示相应的图片和按钮。

所以这里又需要有一个变量加在作用域链末端,用于表示是否已经初始化。

init=function(){
  createBtn();
  createArrow();
  $.delegateTag(wrapSelec+" "+".carousel-btn","a","click",function(e,target){
    $.prevent(e);
    light(target.getAttribute("index"));
    animate.liner(ele,"scrollLeft",target.getAttribute("index")*width);
  });
  $.add(container,"mouseenter",function(){
    stop();
    removeClass(container,"hide");
  });
  $.add(container,"mouseleave",function(){
    addClass(container,"hide");
    begin=setTimeout(circle,t); 
  });if (direction==="forward") {
    light(0);
  }else{
    light(len-1);
    ele.scrollLeft=width*(len-1);
  }
  haveStart=true;
}
登入後複製

9.开始轮播函数 start

这个函数当做接口,用于控制轮播方向,间隔时间,和是否循环。计数器归零。

因为可能重复的开始轮播,所以每次开始之前都需要清除定时器。

start=function(dir,th,lo){
  stop();
  count=0;
  direction=dir;
  t=th*1000;
  loop=lo;
  if (!haveStart) {
    init();
  }
  begin=setTimeout(circle,t);
}
登入後複製

到这里,所有需要用到的函数已经写完了,如果把这些函数和那些需要的变量扔到一个函数里,把外层容器盒包裹容器的类名或ID传给它,这个函数返回一个包含start和stop方法的对象,这个组件就可以使用了。

但是有一个问题,这个函数只有一个,也就是说,一个页面只能有一个轮播实例。所以,如果想要一个页面能有两个轮播实例都用这个组件的话,就不能把它们扔到一个函数里。那么就只能放到对象里。每个对象有自己的变量,他们共用一组方法。

那么,这些变量就不能直接访问了,需要通过对象的属性访问,即this。

这时候就会出现问题,this是会指向调用它的那个环境,所以当那些变量在事件处理程序中,或是在定时器中被访问的时候,就不能用this,而是要创建一个闭包。

即,在能获取到this时,将this赋值给一个变量,然后在事件处理程序或是定时器中访问这个变量,就会获取到正确的对象。

以init函数为例来改装:

carouselProto.init=function(){
  var that=this;
  this.createBtn();
  this.createArrow();
  $.delegateTag(this.wrapSelec+" "+".carousel-btn","a","click",function(e,target){
    $.prevent(e);
    that.light(target.getAttribute("index"));
    animate.liner(that.ele,"scrollLeft",target.getAttribute("index")*that.width);
  });
  $.add(this.container,"mouseenter",function(){
    that.stop();
    removeClass(that.container,"hide");
  });
  $.add(this.container,"mouseleave",function(){
    addClass(that.container,"hide");
    that.begin=setTimeout(function(){
      that.circle();
    },that.t); 
  });if (this.direction==="forward") {
    this.light(0);
  }else{
    this.light(this.len-1);
    this.ele.scrollLeft=this.width*(this.len-1);
  }
  this.haveStart=true;
};
登入後複製

这样改装完之后,就可以创建实例了,每个实例都会有自己的属性用于记录状态,他们都共用原型中的方法。

如果采用原型继承的方式的话,可以创建一个对象作为实例的原型对象,然后创建一个函数来生产实例:

var carouselProto={};
 
//把上面那些方法给这个对象
carouselProto.light=...
carouselProto.go=...
carouselProto.stop=...
 
//创建实例对象函数
var carousel=function(eleSelec,wrapSelec){
  var that=Object.create(carouselProto);
  that.wrapSelec=wrapSelec;
  that.ele=$(eleSelec);
  that.container=$(wrapSelec);
  that.len=that.ele.getElementsByTagName("img").length;
  that.width=parseInt(getCSS(that.ele.getElementsByTagName("img")[0],"width"));
  return that;
}
 
//创建实例,使用组件
var carousel1=carousel(".carousel",".carousel-box");
   carousel1.start("forward",3,true);
var carousel2=carousel(".carousel2",".carousel-box2");
   carousel2.start("backward",2,true);
登入後複製

性能优化:

1.当点击的按钮刚好是当前被点亮的按钮时,依然会调用一次light和animate.liner。所以可以添加一个判断语句,如果点击的按钮刚好是正确的,就不要执行下面的了。

$.delegateTag(this.wrapSelec+" "+".carousel-btn","a","click",function(e,target){
  $.prevent(e);
  var index=target.getAttribute("index");
  if (index===that.active.getAttribute("index")) {
    return
  }
  that.light(index);
  animate.liner(that.ele,"scrollLeft",target.getAttribute("index")*that.width);
});
登入後複製

2.当图片切换的时候,缓动动画正在执行。如果在缓动动画还没执行完时就点击按钮或者箭头,就会进入下一次动画,于是就会出现混乱,图片错位。性能也会受到影响。为了防止这种情况发生,可以使用一个变量,用于记录缓动动画是否正在执行,没有执行的话点击按钮或箭头才会执行函数。

liner=function(ele,prop,next){
  var speed=(next-ele[prop])/10,
    i=0;
  ele.animating=true;
  (function(){
    ele[prop]+=speed;
    i++;
    if (i<10) {
      setTimeout(arguments.callee,60);
    }else{
      ele.animating=false;
    }
  })();  
}
if (!this.ele.animating) {
  this.light(nextIndex);
    animate.liner(this.ele,"scrollLeft",nextPosition);
}
登入後複製


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板