有些事现在不做,以后就不会做了。这句话被我在N种场合下用了N次之后,我终于重新翻开4年前买的《JavaScript DOM编程艺术》了,老老实实的开始重头学JavaScript了。
写JavaScript的思维与CSS相差太大了,以至于现在还是云里雾里的,运用这些天学的粗浅的JavaScript和DOM知识绞尽脑汁写个轮播图,回顾一下整个思路,路过的高手请多多指点。
先出个网页的基本HTML结构:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Javascript Sliders Demo</title>
</head>
<body>
<header>
<h1>JavaScript Sliders</h1>
</header>
<article>
<div id="slider_box">
<button id="prev"> « </button>
<button id="next"> » </button>
<ul id="slider">
<li><img src="images/1.jpg" width="600" height="400" alt="1" title="1"></li>
<li><img src="images/2.jpg" width="600" height="400" alt="2" title="2"></li>
<li><img src="images/3.jpg" width="600" height="400" alt="3" title="3"></li>
<li><img src="images/4.jpg" width="600" height="400" alt="4" title="4"></li>
<li><img src="images/5.jpg" width="600" height="400" alt="5" title="5"></li>
</ul>
</div>
</article>
<footer>2012 © prower.cn</footer>
</body>
<html>
再填入相应的CSS样式,以让页面更好看些:
<style>
* {margin:0; padding:0;}
body {background:rgba(240,240,240,.8); font:14px/1.5 Tahoma,Verdana,Arial; width:950px; margin:0 auto;}
header {margin:20px 0;}
#slider_box {width:600px; height:400px; overflow:hidden; position:relative;}
#slider_box button {background:rgba(0,0,0,.6); border:1px solid rgba(0,0,0,.7); border-radius:17px; box-shadow:0 0 3px rgba(0,0,0,1); color:rgba(255,255,255,1); cursor:pointer; font-size:17px; font-weight:500; width:32px; height:32px; text-align:center; vertical-align:middle; position:absolute; top:184px; z-index:999;}
#slider_box button:hover {background:rgba(255,255,255,1); border-color:rgba(240,240,240,1); color:rgba(0,0,0,1);}
#slider_box li {list-style:none; position:absolute; top:0;}
#prev {left:10px;}
#next {right:10px;}
#slider {position:absolute; top:0;}
footer {font-size:12px; color:rgba(150,150,150,1); margin:20px 0;}
</style>
这样一个静态的HTML页面就好了,结构层跟表现层都具备了,接下去是需要加入JavaScript,赋予它行为层。
因为轮播图是想要滚动的效果,而非隐现的效果,所以需要将图片列表使用绝对定位一字排开来,通过getElementById以及getElementsByTagName遍历出图片列表的HTML结构,并通过for循环为每个li标签追加上样式。为避免浏览器不支持预留退路,在声明函数的同时先加一个判断:
function sliderShow() {
if(!document.getElementById && !document.getElementsByTagName) return false;
var slide = document.getElementById("slider");
var slideli = slide.getElementsByTagName("li");
for(var i=0; i<slideli.length; i++) {
slideli[i].style.left += i * 600 + "px";
}
如果滚动时是修改li的left的值的话,那么滚动一次就要把所有的li的left值都修改一遍,这样太复杂了。既然li已经通过JavaScript分别追加了样式上去,并且都是绝对定位,那么滚动的时候只需要滚动ul这个元素就可以了。
先将HTML里的两个button元素以及ul元素赋值给变量以方便操作,同时为ul元素追加用于滚动时的样式,并通过parseInt将这个字符串转换成数值以便于操作:
var prev = document.getElementById("prev"), next = document.getElementById("next");
var sli = document.getElementById("slider");
sli.style.marginLeft = "0";
var xpos = parseInt(sli.style.marginLeft);
根据li元素的宽度,要显示滚动的话,等于是点击一下button需要滚动相应的正负600px,而当超出最大或最小值时,这个函数就要停止,否则会陷入一直滚动且这个值越来越大不会被清除,然后将每一点点击所获得的最新值传递给ul:
next.onclick = function() {
if(xpos < = -2400) { return false; } else { xpos -= 600; sli.style.marginLeft = xpos + "px"; } } prev.onclick = function() { if(xpos >= 0) {
return false;
} else {
xpos += 600;
sli.style.marginLeft = xpos + "px";
}
}
最后,当网页载入的时候,执行这个函数:
window.onload = sliderShow;
这样一个简单的轮播图效果就做好了,但是当点击button切换图片时,却一点没有滚动的效果!因为每一次Button的点击都是以600px做为一个单位,而并非是以600px做为一个区间,有一个渐加或是渐减的行为。
于是再写一个有一个逐步过程的moveElement()函数:
function moveElement(elementID,gap,interval) {
var elem = document.getElementById(elementID);
var xpos = parseInt(elem.style.marginLeft);
if(xpos == gap) return true;
if(xpos > gap || xpos < gap) {
var glist = Math.floor((gap - xpos)/10);
xpos = xpos + glist;
}
elem.style.marginLeft = xpos + "px";
var move = "moveElement('"+elementID+"',"+gap+","+interval+")";
movement = setTimeout(move,interval);
}
同样需要对之前的sliderShow()函数里点击的部分进行一些修改,当产生点击行为时运行moveElement()函数,并且每运行一次对ul的margin-left属性值进行一个600px的加或减,当margin-left的值位于位移的位置之间时函数才执行:
var elem = document.getElementById("slider");
if(!elem.style.marginLeft) {
elem.style.marginLeft = "0";
}
var xpos = parseInt(elem.style.marginLeft);
next.onclick = function() {
if(xpos > 0 || xpos <= -2400) return false;
moveElement("slider",xpos -= 600,20);
}
prev.onclick = function() {
if(xpos >= 0 || xpos < -2400) return false;
moveElement("slider",xpos += 600,20);
}
这里的渐进效果是有一个累加的过程,所以使用Math对象的floor属性来调整输出为“小于”方向的整数,但只有当点击Next的按钮时,使用Math.floor取出来的值才是正确的,而点击Prev按钮时,这个值就不正确,因为这之间有一个大与小的区别,于是对这里再做一些修正:
if(xpos > gap) {
var glist = Math.floor((gap - xpos)/10);
xpos = xpos + glist;
}
if(xpos < gap) {
var glist = Math.ceil((gap - xpos)/10);
xpos = xpos + glist;
}
这样有一个缓冲滚动效果的轮播就做好了,但是,每一次点击都要小心翼翼的,因为如果当上一次的点击触发的moveElement()函数还没有执行完的话,再进行一次点击,就会导致函数的计算出错,就永远也到不了想到的位置。于是需要使用clearTimeout()函数清除积累在setTimeout队列里的事件:
if(elem.movement) {
clearTimeout(elem.movement);
}
这个的前提是将全局变量movement转变成elem的属性
elem.movement = setTimeout(move,interval);
这样一个基本款的轮播功能就实现了,演示地址及全部源码看这里:JavaScript Slider
路过的高手请指点一下思路里的不周之处以及更优雅的实现方法,谢谢!