原生JS改變透明度實(shí)現(xiàn)輪播效果
在我看來要想實(shí)現(xiàn)輪播主要是要知道當(dāng)前位于的頁面和即將位于的頁面。這個(gè)案例是通過改變圖片的透明度來實(shí)現(xiàn)輪播的效果。
我把涉及的知識(shí)點(diǎn)分為兩個(gè)方面,分別是HTML+css和JS。
第一部分(html+css)
包含的知識(shí)有:positon定位。
最外層是一個(gè)div,它包含了所有的元素。這個(gè)輪播一共有三張圖片,這三張圖片包含在一個(gè)無序列表中。最外層的div還有兩個(gè)用來切換上一張圖片和下一張圖 片的子元素。這兩個(gè)子元素也是div,切換上一張圖片的div的id屬性為pre,切換下一張圖片的div的id屬性為next。最外層div的 position值為relative。包含圖片的無序列表的position為relative。無序列表中的li元素的positon屬性值為 absolute,這會(huì)讓li元素位于文檔流之外,所以如果不顯示的設(shè)置ul的高度,ul高度為零。但是我們不能用css去顯示設(shè)置ul的高度。因?yàn)樾枰?讓這個(gè)輪播的高度等于圖片的高度,并且要保證在不同分辨率的計(jì)算機(jī)上圖片的高寬比保持不變。在不同分辨率的計(jì)算機(jī)上圖片顯示出的高度和寬度是不一樣的。所 以我是通過js去設(shè)置ul的高度。因?yàn)閡l的position的屬性值為relative,所以u(píng)l的高度會(huì)撐開外層div的高度。由于這個(gè)案例是通過改 變圖片透明度實(shí)現(xiàn)輪播,所以所有的圖片位于同一個(gè)位置,在默認(rèn)情況下最后一張圖片會(huì)在最上面,第一個(gè)圖片是在最下面,而輪播第一張顯示的圖片圖片應(yīng)該是第 一張,然后是第二張,最后才是第三張,所以要顯示的對(duì)每個(gè)li設(shè)置z—index屬性。并且z-index屬性值依次遞減。我是用js去設(shè)置每一個(gè)li的 z-index屬性值,但其實(shí)并沒有必要這樣做,直接用css屬性就可以了,只不過要寫三個(gè)選擇器。
html如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>通過改變透明度實(shí)現(xiàn)輪播</title> <link rel="stylesheet" type="text/css" href="index.css" rel="external nofollow" > </head> <body> <div class='warp' id='warp'> <ul class='list' id='list'> <li><img src='img/4274ad202b27b671e622388989399d54.jpg' style='opacity: 1'></li> <li><img src='img/299733ddbe89d6b317cc0e84c43999d4.jpg' style='opacity: 1'></li> <li><img src='img/9b7ec36280e638929aa10ce0955df3d3.jpg' style='opacity: 1'></li> </ul> <div class='pre' id='pre'>《</div> <div class='next' id='next'>》</div> </div> <script type="text/javascript" src='index.js'></script> </body> </html>
css代碼如下
*{
padding: 0;
margin: 0;
}
.warp{
position: relative;
width: 100%;
}
.list{
position: relative;
width: 100%;
}
.list li{
position: absolute;
top:0;
left: 0;
width: 100%;
list-style: none;
opacity: 1;
}
li img{
width: 100%;
}
.pre,.next{
position: absolute;
top: 50%;
bottom: 0;
width: 64px;
height: 64px;
z-index: 10;
margin-top: -32px;
text-align: center;
line-height: 64px;
color: #fff;
font-weight: bold;
font-size: 30px;
cursor: pointer;
background-color: transparent;
}
.pre{
left: 20px;
right: auto;
}
.next{
right:20px;
left: auto;
}
.pre:hover,.next:hover{
background-color: rgba(0,0,0,0.7);
}
第二部分(js)涉及的知識(shí)有:事件,函數(shù)節(jié)流,設(shè)置定時(shí)器,清除定時(shí)器
事件由于用的是原生js去實(shí)現(xiàn)功能,所以需要考慮瀏覽器兼容問題。
事件流
有 兩種類型的時(shí)間流,分別是事件冒泡流和事件捕獲流,這差不多是完全相反的事件流概念,事件冒泡流叫做事件冒泡,這是IE提出的。以一個(gè)click事件為 例,在事件冒泡中事件首先發(fā)生在最具體的那個(gè)元素上,也就是我們單擊的那個(gè)元素,然后沿著dom樹向上傳播,在傳播的過程中,每一級(jí)節(jié)點(diǎn)都會(huì)發(fā)生 click事件,直到傳播的document對(duì)象。事件捕獲流叫做事件捕獲,這是由Netscape Communicator提出的。同樣以一個(gè) click事件為例,在事件捕獲中事件首先發(fā)生在最不具體的那個(gè)節(jié)點(diǎn)上(document對(duì)象首先接收到事件),然后沿著dom樹向下傳播,最具體的節(jié)點(diǎn) 最后接收到事件,也就是說,實(shí)際上被點(diǎn)擊的那個(gè)元素最后接收click事件?!癉OM2級(jí)事件”規(guī)定事件流包括三個(gè)階段,分別為事件捕獲階段,處于目標(biāo)階 段和事件冒泡階段。在主流瀏覽器中除了IE不支持DOM事件流,其他瀏覽器都支持DOM事件流。所以IE之支持事件冒泡。但是在將來IE應(yīng)該會(huì)支持DOM 事件流。那時(shí)候在綁定事件的時(shí)候就不用考慮瀏覽器兼容問題了。目前為了最大程度的兼容各種瀏覽器,我將事件處理程序添加到事件流的冒泡階段。
事件處理程序
》DOM0級(jí)事件處理程序
DOM0 級(jí)使用為元素的屬性賦值的方式綁定事件,將事件處理程序?qū)傩缘闹翟O(shè)置為一個(gè)函數(shù)即可。程序中的this指當(dāng)前元素。刪除通過DOM0級(jí)方法綁定的事件方法 是:將事件處理程序的屬性設(shè)置為null。如果一個(gè)元素綁定了事件,在把這個(gè)元素移除文檔之前,最好手動(dòng)的的解除這個(gè)元素綁定的事件。這樣可以防止元素已 經(jīng)被移除了但是該元素的事件處理程序的引用還保持在內(nèi)存中。所以的現(xiàn)代瀏覽器都支持DOM0級(jí)事件處理程序。但是用DOM0級(jí)綁定事件時(shí),每個(gè)元素同一個(gè) 事件只能添加一個(gè)事件處理程序。
》DOM2級(jí)事件處理程序
在“DOM2級(jí)事件”中指定事件處理程序的方法為:addEventListener(),第一個(gè)參是一個(gè)事件名,第二個(gè)參數(shù)為一個(gè)事件處理程序(即一個(gè)函 數(shù),可以是匿名函數(shù)),第三個(gè)參數(shù)是一個(gè)布爾值。這個(gè)布爾值表示在哪一個(gè)階段處理事件,當(dāng)為false時(shí)表示在冒泡階段處理,當(dāng)為true時(shí)表示在捕獲階 段處理。為了兼容性我將這個(gè)值設(shè)置為false。解除用“DOM2級(jí)事件”綁定的時(shí)間處理程序,需要使用removeEventListener(),匿 名的事件處理程序不能被解除。使用“DOM2級(jí)事件”綁定事件時(shí),每個(gè)元素同一個(gè)事件可以添加多個(gè)事件處理程序。用“DOM2級(jí)事件”綁架的事件處理程 序,this是指當(dāng)前元素。
》IE事件處理程序
在IE中指定事件處理程序的方法是 attachEvent(),第一個(gè)參數(shù)是事件處理程序名(即“on”+事件名),第二個(gè)參數(shù)是時(shí)間處理程序(一個(gè)函數(shù),可以是匿名函數(shù))。由于IE只支 持事件冒泡所以事件在冒泡階段處理。使用detachEvent()可以移除用attachEvent()添加的時(shí)間處理程序,但是匿名函數(shù)不能被移除。 使用attachEvent()綁定事件this指window。。使用attachEvent綁定事件時(shí),每個(gè)元素同一個(gè)事件可以添加多個(gè)事件處理程序。
注:匿名函數(shù)不能被移除的原因是:在js中函數(shù)是一個(gè)對(duì)象,這個(gè)對(duì)象被保存在堆里,函數(shù)名是一個(gè)指針,指向堆里的對(duì)象。對(duì)于一個(gè)匿名函數(shù)而言沒有指針指向它,所以就訪問不到。
事件對(duì)象
在兼容DOM的瀏覽器中,事件對(duì)象是作為一個(gè)參數(shù)傳遞到事件處理程序中。(即在兼容DOM的瀏覽器,不論是通過DOM0級(jí)或DOM2級(jí)綁定事件,都會(huì)將事件 對(duì)象作為參數(shù)傳遞到事件處理程序中),當(dāng)時(shí)IE瀏覽器中,如果用DOM0級(jí)指定時(shí)間處理程序,事件對(duì)象是保存在window的event屬性中,如果用 attachEvent()指定時(shí)間處理程序,事件對(duì)象是作為一個(gè)參數(shù)傳遞到事件處理程序中。在兼容DOM的瀏覽器的事件對(duì)象中的值和IE的事件對(duì)象中的 值存在差異。但它們都有一個(gè)共同的值——type(即:被觸發(fā)的時(shí)間的類型)。在兼容DOM的瀏覽器中,事件對(duì)象的target屬性表示事件的目標(biāo),以一 個(gè)click事件為例,target屬性指最具體的那個(gè)元素。在IE瀏覽器中,事件對(duì)象的srcElement屬性表示事件目標(biāo)
在這個(gè)案例中,我為最外層的div(它的id為warp)添加了一個(gè)click的事件處理程序。通過判斷事件目標(biāo)的id值確定觸發(fā)事件最具體的那個(gè)節(jié)點(diǎn)。如果事件目 標(biāo)的id值為pre則切換到上一個(gè)圖片,如果事件目標(biāo)的id值為next則切換到下一張圖片。這兒用的是事件代理,事件代理可以減少使用的內(nèi)存。
函數(shù)節(jié)流在這個(gè)案例中使用函數(shù)節(jié)流是為了減少當(dāng)連續(xù)觸發(fā)resize事件時(shí)瀏覽器的計(jì)算量,因?yàn)槿绻麨g覽器的計(jì)算量太大,瀏覽器會(huì)變慢,甚至崩潰。函數(shù)節(jié)流的主要思 路是當(dāng)事件被觸發(fā)時(shí),在事件處理程序中,并不是立即做計(jì)算,而是使用setTimeout或者setInterval在指定的時(shí)間后進(jìn)行計(jì)算。
設(shè)置定時(shí)器和清除定時(shí)器由于要完全講清楚定時(shí)器還涉及瀏覽器線程和js的單線程執(zhí)行等問題現(xiàn)在不做講解。主要是我也還沒有完全的搞明白。在這里提一下瀏覽器是多線程的,開啟定時(shí)器 是在瀏覽器的定時(shí)器線程,js執(zhí)行程序是在瀏覽器的另一個(gè)線程。瀏覽器除了這兩個(gè)線程還沒有其他的線程。等我也明白了瀏覽器線程之間的聯(lián)系以后我會(huì)再寫一 篇文章。
在這個(gè)實(shí)例中改變圖片的透明度是通過設(shè)置定時(shí)器逐漸變大或者逐漸變小。在增加下一張圖片的不透明度之前,要先將當(dāng)前圖片的不透名都減小到0。
打開頁面自動(dòng)播放,也是用定時(shí)器實(shí)現(xiàn)的,如果要停止播放,就清除定時(shí)器
js代碼如下
// 當(dāng)頁面加載完成后將所以需要執(zhí)行的函數(shù)添加到window的load事件上。這兒用的是dom0級(jí)事件的綁定,所以不能為window的load事件添加 多個(gè)事件處理程序,所以使用的方法是:先判斷window.onload有沒有綁定函數(shù),如果綁定了,就將新的函數(shù)追加到尾部,如果沒有綁定,就直接添加 給它。用attachEvent()或者addEventListener()可以為同一個(gè)元素的同一個(gè)事件綁定多個(gè)事件處理程序,可以不用下面這個(gè)方法。
function addLoadEvent(func){
var oldLoad = window.onload;
if(typeof oldLoad != 'function'){
window.onload = func();
}else{
window.onload = function(){
oldLoad();
func();
}
}
}
//設(shè)置class為list的高度,因?yàn)閳D片的position為absolute所以.list元素的高度為零
//如果一個(gè)元素的父元素高度為0,那么設(shè)置這個(gè)元素的margin: auto 0; 不起作用
function setListHeight(){
var list = document.getElementById('list');
var imgItem = list.getElementsByTagName('img')[0];
var height = imgItem.offsetHeight;
var list = document.getElementById('list');
list.style.height = height + 'px';
}
//設(shè)置li的層級(jí),可以使用css設(shè)置
function setLiIndex(){
var list = document.getElementById('list');
var li = list.getElementsByTagName('li');
var liLen = li.length;
for(var i = 0;i<liLen;i++){
li[i].style.zIndex = liLen-i;
}
}
var index = 1;//index表示當(dāng)前顯示的頁面,index是一個(gè)全局變量
var timer;// 定時(shí)器標(biāo)識(shí)符,如果要清除定時(shí)器需要使用它
//事件的跨瀏覽器綁定的對(duì)象
var untilEvent = {
addEvent:function(element,type,hander){
if(element.addEventListener){
element.addEventListener(type,hander,false);
}else if(element.attachEvent){
element.attachEvent('on'+type,hander);
}else{
element['on'+type] = hander;
}
},
getEvent:function(event){
return event?event:window.event;
},
getTarget:function(event){
return event.target||event.srcElement;
}
};
function btnClick(){
var warp = document.getElementById('warp');
untilEvent.addEvent(warp,'click',function(event){
var event = untilEvent.getEvent(event);
var target = untilEvent.getTarget(event);
switch(target.id){
case 'pre': if(index == 1){//如果當(dāng)前顯示的圖片已經(jīng)是第一張圖片,當(dāng)點(diǎn)擊切換到"上一張"按鈕,則將即將顯示的圖片設(shè)置為最后一張圖片
index =3;
}else{
--index;
}
anmitate();
break;
case 'next':if(index == 3){//如果當(dāng)前顯示的圖片已經(jīng)是最后圖片,當(dāng)點(diǎn)擊切換到"下一張"按鈕,則將即將顯示的圖片設(shè)置為第一張圖片
index = 1;
}else{
++index;
}
anmitate();
break;
}
});
}
//減小圖片透明度
function decline(cur,inverTime,inverOpacity){
var opacityed = parseFloat(cur.style.opacity);
if(opacityed > 0){
cur.style.opacity = opacityed-inverOpacity;
setTimeout(function(){
decline(cur,inverTime,inverOpacity);
},inverTime);
}
}
//切換圖片的函數(shù)
function anmitate(){
var list = document.getElementById('list');
var imgs = list.getElementsByTagName('img');
var imgsLen = imgs.length;
var whole = 300;//切換一張圖片用的時(shí)間
var inverTime = 5;//時(shí)間間隔
var inverOpacity = 1/(whole/inverTime);
for(var i = 0;i<imgsLen;i++){
decline(imgs[i],inverTime,inverOpacity);
}
var go = function(){
var opacityed = parseFloat(imgs[index - 1].style.opacity);
if(opacityed < 1){
imgs[index-1].style.opacity = opacityed + inverOpacity;
setTimeout(go,inverTime);
}
};
go();
}
//打開頁面自動(dòng)切換函數(shù)
function play() {
timer = setTimeout(function () {
if(index == 3){
index = 1;
}else{
++index;
}
anmitate();
play();
//
}, 3000);
}
//停止切換函數(shù),當(dāng)鼠標(biāo)移動(dòng)到輪播上后取消自動(dòng)切換,當(dāng)鼠標(biāo)從輪播上移開,又開始自動(dòng)切換
function stop() {
clearTimeout(timer);
}
//給最外層div添加鼠標(biāo)移除和鼠標(biāo)移入地事件處理程序
function getWarp(){
var warp = document.getElementById('warp');
untilEvent.addEvent(warp,"mouseout",play);
untilEvent.addEvent(warp,"mouseover",stop);
}
//函數(shù)節(jié)流,當(dāng)改變窗口大小時(shí),圖片的大小會(huì)變化,所以為了讓控制按鈕位于輪播垂直方向的中間,li的高度該隨圖片的大小做變化
function scrollEvent(){
untilEvent.addEvent(window,"resize",function(){
throttle(setListHeight);
});
}
function throttle(method,context){
clearTimeout(method.Tid);
method.Tid = setTimeout(method,70);
}
addLoadEvent(scrollEvent);
addLoadEvent(setListHeight);
addLoadEvent(setLiIndex);
addLoadEvent(btnClick);
addLoadEvent(play);
addLoadEvent(getWarp);
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JS實(shí)現(xiàn)短信驗(yàn)證碼一鍵登錄功能
短信驗(yàn)證碼一鍵登錄是一種方便快捷的登錄方式,本文介紹了其原理并給出了一個(gè)簡(jiǎn)單的JavaScript示例,感興趣的朋友跟隨小編一起看看吧2024-05-05
Bootstrap modal 多彈窗之疊加顯示不出彈窗問題的解決方案
Bootstrap modal 多彈窗之疊加顯示不出彈窗問題,今天小編抽時(shí)間給大家分享下解決方案,需要的朋友參考下2017-02-02
[Web]防止用戶復(fù)制頁面內(nèi)容和另存頁面的方法
原理就是利用js控制一些復(fù)制等事件,但破解也簡(jiǎn)單,這里就不說了。2009-02-02
為JavaScript類型增加方法的實(shí)現(xiàn)代碼(增加功能)
大家在js開發(fā)過程中有些功能已經(jīng)滿足不了我們的需求,或沒有我們需要的功能,那么我們就可以自己擴(kuò)展下,個(gè)性化js2011-12-12
window resize和scroll事件的基本優(yōu)化思路
在項(xiàng)目中使用scroll事件去加載數(shù)據(jù),結(jié)果IE下悲劇了。下面為大家介紹下window resize和scroll事件的基本優(yōu)化思路,需要的朋友可以參考下2014-04-04

