经常在做网页中遇到需要展示一组或几组图片的情况,于是图片的无缝滚动效果成为比较常见的效果之一。往往我们时间有限,所以常求助于jQuery的图片滚动插件。
前段时间,我觉得仅仅需要一个这样的特效而把整个jQuery库引入项目中实在太耗费性能,于是自己动手做了一个,下面是简陋的雏形:
原理比较简单,就是在页面初始化时将首尾的图片各复制一个分别放至结尾和开头,如下图所示:
1、2、3代表3组滚动的图片,1号结点为起始位置,当点击右按钮时,图片从1号结点向右滚动,直到clone3结点,结束后立即将位置从clone3定位到3号结点;再点击向右按钮时,就从3号结点滚动到2号结点,
这样看起来就实现了无缝滚动,点击左按钮与点击右按钮的原理相同。
函数中主要包含两个方法:
init方法——该方法做一些初始化操作,比如记录每组图片当前的位置,一共几组图片,克隆首尾结点等;
animate方法——该方法执行点击了左或右按钮后的动画效果
以下是init方法的一些代码:
1 init:function(params) { 2 params = params || {}; 3 //获取外层容器对象 4 this.target = params.id || $('b'); 5 //是否自动滚动 6 this.autoScroll = params.autoScroll || false; 7 //用于保存间歇函数 8 this.t = null; 9 //将容器的属性保存至局部变量 10 var p = this.target.getBoundingClientRect(); 11 //计算容器的宽度,IE没有width属性,故用后者代替 12 this.width = p.width || p.right - p.left; 13 //获取内层容器 14 this.box = getElementsByClass('c')[0]; 15 //定义一个数组用于保存内层容器内的子节点,即共有几组滚动图片 16 var nodeArr = []; 17 for(var i = 0,len = this.box.childNodes.length; i < len; i++) { 18 /* 19 *由于可能取到的结点可能为文本,必须排除文本节点 20 *元素节点类型取值(nodeType) 21 *元素element 1 22 *属性attr 2 23 *文本text 3 24 *注释comments 8 25 *文档document 9 26 */ 27 if(this.box.childNodes[i].nodeType == 1) { 28 //将符合的节点推入数组 29 nodeArr.push(this.box.childNodes[i]); 30 } 31 } 32 //将需要滚动图片的数量保存到一个变量 33 this.num = nodeArr.length; 34 //克隆首尾的节点 35 var first = nodeArr[0], 36 last = nodeArr[nodeArr.length - 1], 37 firstClone = first.cloneNode(true), 38 lastClone = last.cloneNode(true); 39 //将克隆的节点新增clone样式作为标识 40 firstClone.className = lastClone.className = 'd clone'; 41 //分别将末节点和首节点的克隆添加到第一位和最后一位 42 this.box.insertBefore(lastClone,first); 43 this.box.appendChild(firstClone); 44 45 //获取左按钮和右按钮 46 this.parent = this.target.parentNode; 47 var prev = getElementsByClass('prev',this.parent,'a')[0], 48 next = getElementsByClass('next',this.parent,'a')[0]; 49 50 //初始化位置 51 var w = this.width;//保存每组滚动图片(一组四张图片)的宽度 52 /*将开始位置设置为第一组滚动图片,在第一组滚动图片前有一个clone节点,left值为0 53 故第一组的滚动图片的位置为-this.width*/ 54 this.box.style.left = -this.width + 'px'; 55 56 //设置缓动函数的相关变量 57 this.b = -w; //由于是从第一组图片开始的,所以初始位置为一组图片的宽度,方向为负(左为正方向) 58 this.c = -w; //位移,即滚动一次经过的路程,方向为负(左为正方向),值和每组图片的宽度相等 59 this.d = 50; //缓动的总时间 60 this.t = 0; //当前经过的时间 61 62 //定义一个数组,用来保存每组图片的位置 63 this.initPos = []; 64 //每一组滚动图片对应一个索引,初始化时将索引至为1 65 this.index = 1; 66 //加上克隆的节点,一共有this.num + 2个节点 67 for(var j = 0,num = 0,l = this.num+2; j < l; j++) { 68 this.initPos.push(-w * num++); 69 } 70 71 //console.log(this.initPos); //[0,-600,-1200,-1800,-2400] 72 73 //设置布尔值,判断动画是否完成 74 this.prevAllow = true; 75 this.nextAllow = true; 76 var self = this; 77 //添加左右按钮单击事件 78 addEvent(prev,'click',self.animate.bind(self,'left')); 79 addEvent(next,'click',self.animate.bind(self,'right')); 80 81 //如果开启自动滚动则每三秒滚动一次 82 this.autoScroll && (this.t = setInterval(function() { 83 self.animate('left'); 84 },3000));
},
在该方法的最后注册了左右按钮的点击事件,调用的是animate方法:
1 /* 2 * 点击左右按钮时执行的操作 3 * @param {string} left || right 传入的参数表示点击了哪边的按钮 4 */ 5 animate:function(button) { 6 var self = this, 7 //获取滚动容器 8 box = this.box, 9 boxStyle = box.style; 10 11 switch(button) { 12 case 'left': 13 if(this.prevAllow) { 14 //防止在动画完成前连续点击按钮进行多次操作 15 this.prevAllow = false; 16 //将初始位置设置为当前的索引值 17 this.b = this.initPos[this.index]; 18 //每点一次左按钮,索引加1,若超过索引最大值则返回0,表示滚动到头需要重新从第一组开始 19 this.index = (this.index > this.initPos.length - 1) ? 0 : this.index + 1; 20 //设置需要的位移,方向向左,负值 21 this.c = this.initPos[1]; 22 //每点一次需要将当前时间重置为0以免受到上一次计时的影响 23 this.t = 0; 24 (function() { 25 //使用缓动函数计算位移,直至动画完成 26 boxStyle.left = easeOut(self.t,self.b,self.c,self.d) + 'px'; 27 if(self.t < self.d) { 28 self.t++; 29 setTimeout(arguments.callee,15); 30 } else {//动画完成后解除连续点击按钮锁定 31 self.prevAllow = true; 32 } 33 //假如向左滚动到最后一组图片(clone),则将其left设置为第一组图片 34 if(parseInt(boxStyle.left) == self.initPos[self.initPos.length-1]) { 35 boxStyle.left = self.initPos[1] + 'px'; 36 //同时重置索引 37 self.index = 1; 38 } 39 })(); 40 } 41 break; 42 case 'right': //点击向右按钮时 43 if(this.nextAllow) { 44 //防止在动画完成前连续点击按钮进行多次操作 45 this.nextAllow = false; 46 //将初始位置设为当前的索引值 47 this.b = this.initPos[this.index]; 48 //更新索引 49 this.index = (this.index > 0) ? this.index - 1 : this.initPos.length - 1; 50 //设置需要的位移,方向向右,正值 51 this.c = -this.initPos[1]; 52 //每点一次需要将当前时间重置为0以免受到上一次计时的影响 53 this.t = 0; 54 (function() { 55 //使用缓动函数计算位移,直至动画完成 56 boxStyle.left = easeOut(self.t,self.b,self.c,self.d) + 'px'; 57 if(self.t < self.d) { 58 self.t++; 59 setTimeout(arguments.callee,15); 60 } else {//动画完成后解除连续点击按钮锁定 61 self.nextAllow = true; 62 } 63 //假如向右滚动到第一组图片(clone节点),则将其left设置为最后一组图片 64 if(parseInt(boxStyle.left) == self.initPos[0]) { 65 boxStyle.left = self.initPos[self.initPos.length-2] + 'px'; 66 //同时将索引重置为当前组的索引 67 self.index = self.initPos.length-2; 68 } 69 })(); 70 } 71 break; 72 default: 73 break; 74 } 75 } 76 };
最后是构造函数:
1 function Scroll() { 2 return this.init.apply(this,arguments); 3 } 4 5 Scroll.prototype = { 6 init:function(){/*code*/}, 7 animate:function(){/*code*/} 8 }
new Scroll();
虽然没有jQuery插件中强大的功能,比如传入横向或竖直滚动的参数,设置是否无缝滚动等,但基本也算满足了项目的需要,同时代码体积缩小了不少。
由于没有研究过jQuery插件实现这种效果的代码,效果是实现了,但代码和逻辑都不算好,还请高手不要鄙视,多多给予意见。
源码:图片无缝滚动
-------------------------------
转载请注明出处。