基于jquery的图片轮播,tab切换组件

  最近在做手机上的web app,很多场景需要使用到类似tab切换和图片轮播的东西,需要支持手势和鼠标点击的,于是就基于jquery弄了一个,每一个参数有详细的说明,目前只添加了scroll和none的效果,scroll即滑动的效果,可以支持x和y方向的滑动;none就是没有任何效果,只是显示和隐藏,后续需要添加其他效果再做扩展,写的有点水,呵呵,在此留笔,防止丢失。更新后的版本,只支持单个图轮播。

  更新内容:将之前使用的用left控制动画修改为使用css3的-webkit-transform来控制动画,流畅度大大提升,另外使用translate3d和translateX来控制图片的位移。如果不支持transform则会使用原来的left来控制图片的位移。

  Demo Address:http://kardel.sinaapp.com/qqbuy/1.html

检测浏览器支持某属性的方法:

// 检查是否支持css属性
var propertySupport = (function () {
    var element = document.createElement("i");
    var eleStyle = element.style;
    var prefix = ' -o- -moz- -ms- -webkit- '.split(' ');
    var domPrefs = 'Webkit Moz O ms'.split(' ');
    return {
        hasProperty:function (prop) {
            var camel = prop.charAt(0).toUpperCase() + prop.substr(1),
                    props = (prop + ' ' + domPrefs.join(camel + ' ') + camel).split(' ');
            for (var i in props) {
                if (eleStyle[props[i]] !== undefined) {
                    return true;
                }
            }
            return false;
        },
        isSupport3D:function () {
            if ('WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix()) {
                return true;
            }
            var css = ['perspectiveProperty', 'MozPerspective', 'OPerspective', 'msPerspective']
            for (var p in css) {
                if (css[p] in eleStyle) {
                    return true;
                }
            }
            return false;
        }
    }
})();

实现代码:

  1 $.fn.loopSlider = function (option) {
  2     function config(opt) {
  3         var setting = {
  4             // 默认显示的顺序
  5             initIndex: 1,
  6             // 加在状态节点上的样式
  7             className: "current",
  8             // 轮播方向,默认为x轴方向轮播
  9             direct: "x",
 10             // 上一张按钮
 11             prevBtn: "",
 12             // 下一张按钮
 13             nextBtn: "",
 14             // 上下翻页按钮禁用的样式
 15             btnDisable: "disable",
 16             // 按钮按下的样式
 17             btnTouchClass: "",
 18             // 自动轮播
 19             auto: false,
 20             // 自动轮播时间间隔
 21             timeFlag: 4000,
 22             // 轮播效果时间
 23             scrollTime: 350,
 24             // 轮播效果
 25             effect: "scroll",
 26             // 在只有一个轮播元素的时候是否隐藏滑动按钮
 27             hideBtn: true,
 28             // 是否循环轮播
 29             cycle: true,
 30             // 轮播的内容区的容器路径
 31             contentContainer: "",
 32             // 轮播的内容区的节点
 33             contentChildTag: "",
 34             // 标题轮播区域的容器路径
 35             titleContainer: "",
 36             // 标题轮播区域的节点
 37             titleChildTag: "",
 38             // 隐藏的图片链接属性
 39             imgAttr: "back_src",
 40             // 轮播的内容区的数组
 41             cont: [],
 42             // 轮播的标题区的数组
 43             tabs: [],
 44             // 显示数量
 45             showNum: 1,
 46             // 元素间的margin值
 47             gapWidth: 0,
 48             // 轮播回调函数,每次轮播调用,参数为当前轮播的序号
 49             callback: function () {
 50                 return true;
 51             }
 52         }
 53         $.extend(setting, opt);
 54         return setting;
 55     }
 56 
 57     var boss = $(this);
 58     var nodeList = [];
 59     boss.each(function (index) {
 60         nodeList[index] = {
 61             node: $(this),
 62             setting: config(option)
 63         }
 64         handleScroll(nodeList[index]);
 65     });
 66     return {
 67         get: function (index) {
 68             if (nodeList[index]) {
 69                 return nodeList[index];
 70             } else {
 71                 return false;
 72             }
 73         }
 74     };
 75 
 76     function handleScroll(obj) {
 77         var setting = obj.setting;
 78         // 当前页
 79         setting.current = 0;
 80         // 定时器
 81         setting.ptr = "";
 82         var node = obj.node;
 83         setting.imgloadedNum = 0;
 84         // 初始化当前调用类型的函数
 85         setting.currentMethod = function () {
 86             return true;
 87         }
 88         // 如果不是第一个元素先轮播
 89         if (setting.initIndex != 1) {
 90             setting.current = setting.initIndex - 1;
 91         }
 92         // 获取轮播的节点列表
 93         var childList = node.find(setting.contentContainer + " " + setting.contentChildTag);
 94         // 获取轮播标题节点列表
 95         var titleList = node.find(setting.titleContainer + " " + setting.titleChildTag);
 96         // 上下箭头
 97         var nextBtn = node.find(setting.nextBtn);
 98         var prevBtn = node.find(setting.prevBtn);
 99         // 保存内容区每一个轮播节点
100         setting.cont = childList;
101         // 保存标题的轮播节点
102         setting.tabs = titleList;
103         // 如果没有需要轮播的内容,直接返回
104         if (setting.cont.length <= 1) {
105             if (setting.hideBtn) {
106                 prevBtn.hide();
107                 nextBtn.hide();
108             }
109             return;
110         }
111         var withtitle = setting.titleContainer && setting.tabs.length > 0;
112         // 给内容区和标题区设置index属性
113         childList.each(function (index) {
114             $(this).attr("index", index);
115             // 设置了title,但是内容不足,补全
116             if (withtitle && !setting.tabs[index]) {
117                 var first = titleList.eq(0);
118                 var cloneNode = first.clone();
119                 first.parent().append(cloneNode);
120                 cloneNode.attr("index", index);
121             }
122             titleList.eq(index).attr("index", index);
123         });
124         // 如果有添加过状态节点,则重新更新一下状态节点容器
125         if (withtitle && setting.tabs.length != setting.cont.length) {
126             titleList = node.find(setting.titleContainer + " " + setting.titleChildTag);
127             setting.tabs = titleList;
128         }
129         // 长度
130         var counts = childList.length;
131         // 轮播容器的父节点
132         var childParent = childList.parent();
133         var titleParent = titleList.parent();
134         if (childList.length < setting.initIndex) {
135             setting.current = 0;
136         }
137         // 初始化
138         doInit();
139         /**
140          * 处理无效果的切换
141          */
142         var doScrollNone = {
143             process: function () {
144                 var i = setting.current;
145                 loadImage();
146                 childList.eq(i).css("display", "block").siblings().css("display", "none");
147                 titleList.eq(i).addClass(setting.className).siblings().removeClass(setting.className);
148                 // 调用回调函数
149                 setting.callback(setting.current);
150                 if (setting.auto) {
151                     processAuto();
152                 }
153             },
154             init: function () {
155                 setting.currentMethod = doScrollNone;
156                 loadImage();
157                 bindEvent();
158                 // 自动轮播
159                 if (setting.auto) {
160                     processAuto();
161                 }
162                 // 初始化的时候调用回调函数
163                 setting.callback(setting.current);
164             }
165         };
166         var doScrollXY = {
167             init: function () {
168                 // 轮播元素的宽度
169                 setting.c_width = childList.width();
170                 // 轮播元素的高度
171                 setting.c_height = childList.height();
172                 // 克隆第一个元素到最后
173                 if (setting.cycle && childList.length > 1) {
174                     var firstNode = childList.eq(0).clone(true);
175                     var lastNode = childList.eq(counts - 1).clone(true);
176                     if (setting.direct == "x") {
177                         lastNode.css({
178                             position: 'relative',
179                             left: -setting.c_width * (counts + 2)
180                         });
181                     } else {
182                         lastNode.css({
183                             position: 'relative',
184                             top: -setting.c_height * (counts + 2)
185                         });
186                     }
187                     firstNode.attr("index", 0);
188                     firstNode.appendTo(childParent);
189                     lastNode.attr("index", counts - 1);
190                     lastNode.appendTo(childParent);
191                     // 更新列表信息
192                     childList = childParent.children();
193                 }
194                 // x轴方向轮播
195                 if (setting.direct == "x") {
196                     childParent.width(setting.c_width * (setting.cycle ? counts + 2 : counts));
197                     if (setting.transform) {
198                         childParent.css({
199                             "-webkit-backface-visibility": "hidden",
200                             "-webkit-transform": "translateX(" + (-setting.c_width * (setting.current)) + "px)"
201                         });
202                     } else {
203                         childParent.css('left', - setting.c_width * setting.current);
204                     }
205                 } else {
206                     childParent.width(setting.c_width);
207                     childParent.height(setting.c_height * (setting.cycle ? counts + 2 : counts));
208                     if (setting.transform) {
209                         childParent.css({
210                             "-webkit-backface-visibility": "hidden",
211                             "-webkit-transform": "translateY(" + (-setting.c_height * (setting.current)) + "px)"
212                         });
213                     } else {
214                         childParent.css('top', - setting.c_height * setting.current);
215                     }
216                 }
217                 titleList.eq(setting.current).addClass(setting.className).siblings().removeClass(setting.className);
218                 setting.currentMethod = doScrollXY;
219                 // 初始化的时候也调用回调函数
220                 setting.callback(setting.current);
221                 // 绑定事件
222                 bindEvent();
223                 // 自动轮播
224                 if (setting.auto) {
225                     processAuto();
226                 }
227             },
228             process: function () {
229                 var index = setting.current;
230                 var _this = this;
231                 loadImage();
232                 if (setting.direct == "x") {
233                     this.processDirect("left", setting.c_width, index);
234                 } else {
235                     this.processDirect("top", setting.c_height, index);
236                 }
237                 if (index == counts) {
238                     index = 0;
239                 } else if (index == -1) {
240                     index = counts - 1;
241                 }
242                 this.processEnd(index);
243             },
244             processDirect: function (direct, value, index) {
245                 var _this = this;
246                 var trans = direct == "left" ? "translateX" : "translateY";
247                 if (setting.transform) {
248                     childParent.css({
249                         "-webkit-transform": trans + "(" + (-value * index) + "px)",
250                         "-webkit-transition": setting.scrollTime / 1000 + "s ease-out",
251                         "-webkit-backface-visibility": "hidden"
252                     });
253                 } else if (setting.transition) {
254                     childParent.css({
255                         direct: -value * index,
256                         "-webkit-transition": direct + " " + setting.scrollTime / 1000 + "s ease-out",
257                         "-webkit-backface-visibility": "hidden"
258                     });
259                 } else {
260                     childParent.animate({
261                         direct: -value * index
262                     }, setting.scrollTime);
263                 }
264                 setTimeout(function () {
265                     if (setting.is3D) {
266                         childParent.css({
267                             "-webkit-transform": (direct == "left" ? "translate3d(" + (-value * index) + "px,0px,0px)" : "translate3d(0px," + (-value * index) + "px,0px)"),
268                             "-webkit-transition": ""
269                         });
270                     }
271                     if (setting.current == counts && setting.cycle) {
272                         _this.moveElement();
273                     } else if (setting.current == -1) {
274                         if (setting.is3D) {
275                             childParent.css({
276                                 "-webkit-transform": (direct == "left" ? "translate3d(" + (-value * (counts - 1)) + "px,0px,0px)" : "translate3d(0px," + (-value * (counts - 1)) + "px,0px)"),
277                                 "-webkit-transition": ""
278                             });
279                         } else {
280                             childParent.css({
281                                 direct: -value * (counts - 1)
282                             });
283                         }
284                     }
285                     if (setting.auto) {
286                         //非循环并且到了最后一个,停止定时器
287                         !setting.cycle && setting.current == counts - 1 ? "" : processAuto();
288                     }
289                 }, setting.scrollTime);
290             },
291             processEnd: function (index) {
292                 this.updateBtnStatus(index);
293                 // 调用回调函数
294                 setting.callback(index);
295                 titleList.eq(index).addClass(setting.className).siblings().removeClass(setting.className);
296             },
297             updateBtnStatus: function (i) {
298                 if (i == 0 && !setting.cycle) {
299                     setting.prevBtn && prevBtn.addClass(setting.btnDisable);
300                 } else {
301                     setting.prevBtn && prevBtn.removeClass(setting.btnDisable);
302                 }
303                 if (i == counts - 1 && !setting.cycle) {
304                     setting.nextBtn && nextBtn.addClass(setting.btnDisable);
305                 } else {
306                     setting.nextBtn && nextBtn.removeClass(setting.btnDisable);
307                 }
308             },
309             moveElement: function () {
310                 var lastNode = childList.eq(counts + 1);
311                 for (var i = 1; i < childList.length - 2; i++) {
312                     childList.eq(i).remove().insertBefore(lastNode);
313                 }
314                 childList.eq(0).remove().insertBefore(lastNode);
315                 childParent.css({
316                     "-webkit-transform": "translate3d(0px,0px,0px)",
317                     "-webkit-transition": ""
318                 });
319             }
320         };
321         var touchEvent = {
322             startX: 0,
323             startY: 0,
324             currentPosition: 0,
325             start: function (event) {
326                 if (event.changedTouches.length == 0) {
327                     return;
328                 }
329                 var po = touchEvent.getPosition(event);
330                 touchEvent.startX = po.x;
331                 touchEvent.startY = po.y;
332                 //手势滑动方向
333                 var moveDirect = "add";
334                 // 计算当前值的乘积因子
335                 var num = setting.current == -1 ? counts - 1 : setting.current != counts ? setting.current : 0;
336                 // 当前显示元素所处的位置
337                 touchEvent.currentPosition = -num * (setting.direct == "x" ? setting.c_width : setting.c_height);
338                 // 清除定时器
339                 if (setting.ptr) {
340                     clearInterval(setting.ptr);
341                     setting.ptr = null;
342                 }
343                 childParent[0].ontouchmove = touchEvent.move;
344             },
345             move: function (moveEvent) {
346                 var movePo = touchEvent.getPosition(moveEvent);
347                 var moveX = movePo.x;
348                 var moveY = movePo.y;
349                 if (setting.direct == 'x') {
350                     var x = moveX - touchEvent.startX;
351                     // 横坐标和纵坐标的差值超过10个像素,才给滑动
352                     if (Math.abs(x) > Math.abs(moveY - touchEvent.startY)) {
353                         // 阻止默认的事件
354                         moveEvent.preventDefault();
355                         if (setting.is3D) {
356                             childParent.css({
357                                 "-webkit-transform": "translate3d(" + (parseFloat(touchEvent.currentPosition) + x) + "px,0px,0px)"
358                             });
359                         } else if (setting.transform) {
360                             childParent.css({
361                                 "-webkit-transform": "translateX(" + (parseFloat(touchEvent.currentPosition) + x) + "px)"
362                             });
363                         } else {
364                             childParent.css({
365                                 "left": parseFloat(touchEvent.currentPosition) + x
366                             });
367                         }
368                         moveDirect = x > 0 ? "sub" : "add";
369                     } else {
370                         childParent[0].ontouchmove = null;
371                         return;
372                     }
373                 } else {
374                     // Y轴方向滚动
375                     moveEvent.preventDefault();
376                     var y = moveY - touchEvent.startY;
377                     if (setting.is3D) {
378                         childParent.css({
379                             "-webkit-transform": "translate3d(0px," + (parseFloat(touchEvent.currentPosition) + y) + "px,0px)"
380                         });
381                     } else if (setting.transform) {
382                         childParent.css({
383                             "-webkit-transform": "translateY(" + (parseFloat(touchEvent.currentPosition) + y) + "px)"
384                         });
385                     } else {
386                         childParent.css({
387                             "top": parseFloat(touchEvent.currentPosition) + y
388                         });
389                     }
390                     moveDirect = y > 0 ? "sub" : "add";
391                 }
392                 childParent[0].ontouchend = touchEvent.end;
393             },
394             end: function () {
395                 //根据手指移动的方向,判断下一个要显示的节点序号
396                 if (moveDirect == "add") {
397                     setNext();
398                 } else {
399                     setPrev();
400                 }
401                 // 调用对应的处理函数
402                 setting.currentMethod.process();
403                 childParent[0].ontouchend = null;
404                 childParent[0].ontouchmove = null;
405             },
406             getPosition: function (evt) {
407                 var touch = evt.changedTouches ? evt.changedTouches[0] : evt;
408                 return {
409                     x: touch.clientX,
410                     y: touch.clientY
411                 }
412             }
413         }
414         switch (setting.effect) {
415         case "none":
416             doScrollNone.init();
417             break;
418         case "scroll":
419             doScrollXY.init();
420             break;
421         }
422 
423         // 一些初始化操作
424         function doInit() {
425             childParent.css("position", "relative");
426             if (!setting.cycle) {
427                 prevBtn.removeClass(setting.btnDisable);
428                 nextBtn.removeClass(setting.btnDisable);
429                 if (setting.current == 0) {
430                     prevBtn.addClass(setting.btnDisable);
431                 }
432                 if (setting.current == counts - 1) {
433                     nextBtn.addClass(setting.btnDisable);
434                 }
435             }
436             // 判断是否支持几个属性
437             setting.transform = propertySupport.hasProperty("transform");
438             setting.transition = propertySupport.hasProperty("transition");
439             setting.is3D = propertySupport.isSupport3D();
440             if (setting.effect != "none") {
441                 setting.current == 0 ? initImage() : loadImage();
442             }
443         }
444 
445         // 加载图片,先加载第一个和最后一个图
446         function initImage() {
447             var firstNode = childList.first();
448             var lastNode = childList.last();
449             getImg(firstNode.find("img"));
450             getImg(lastNode.find("img"));
451         }
452 
453         function getImg(img) {
454             if (img.attr(setting.imgAttr)) {
455                 img.attr("src", img.attr(setting.imgAttr));
456                 img.removeAttr(setting.imgAttr);
457             }
458         }
459 
460         function loadImage() {
461             var curNode = childList.eq(setting.current);
462             getImg(curNode.find("img"));
463         }
464 
465         function setPrev() {
466             var cur = parseInt(setting.current, 10);
467             var value = 0;
468             switch (cur) {
469             case 0:
470                 value = setting.cycle ? (setting.effect == "none" ? counts - 1 : -1) : 0;
471                 break;
472             case -1:
473                 value = counts - 2;
474                 break;
475             case counts:
476                 value = -1;
477                 break;
478             default:
479                 value = cur - 1;
480                 break;
481             }
482             setting.current = value;
483             if (setting.ptr) {
484                 clearInterval(setting.ptr);
485                 setting.ptr = null;
486             }
487         }
488 
489         function setNext() {
490             var cur = parseInt(setting.current, 10);
491             var value = 1;
492             switch (cur) {
493             case counts:
494                 value = 1;
495                 break;
496             case -1:
497                 value = counts;
498                 break;
499             case counts - 1:
500                 value = setting.cycle ? (setting.effect == "none" ? 0 : counts) : cur;
501                 break;
502             default:
503                 value = cur + 1;
504                 break;
505             }
506             setting.current = value;
507             if (setting.ptr) {
508                 clearInterval(setting.ptr);
509                 setting.ptr = null;
510             }
511         }
512         /**
513          * 绑定轮播事件
514          */
515         function bindEvent() {
516             setting.nextBtn && nextBtn.bind("click", function () {
517                 // 如果按钮已经被禁用
518                 if ($(this).hasClass(setting.btnDisable)) {
519                     return;
520                 }
521                 setNext();
522                 $(this).addClass(setting.btnTouchClass);
523                 setting.currentMethod.process();
524                 return false;
525             });
526             setting.prevBtn && prevBtn.bind("click", function () {
527                 if ($(this).hasClass(setting.btnDisable)) {
528                     return;
529                 }
530                 setPrev();
531                 $(this).addClass(setting.btnTouchClass);
532                 setting.currentMethod.process();
533                 return false;
534             });
535             childParent[0].ontouchstart = touchEvent.start;
536         }
537         /**
538          * 自动轮播
539          */
540         function processAuto() {
541             if (setting.ptr) {
542                 clearInterval(setting.ptr);
543                 setting.ptr = null;
544             }
545             // 设置轮播定时器
546             setting.ptr = setInterval(function () {
547                 if (setting.current == counts) {
548                     setting.current = 1;
549                 } else if (setting.current == counts - 1) {
550                     setting.current = setting.cycle ? (setting.effect == "none" ? 0 : counts) : counts - 1;
551                     if (!setting.cycle && setting.ptr) {
552                         clearInterval(setting.ptr);
553                         setting.ptr = null;
554                     }
555                 } else {
556                     setting.current = setting.current + 1;
557                 }
558                 setting.currentMethod.process();
559             }, setting.timeFlag);
560         }
561 
562         obj.setIndex = function (index) {
563             if (index < 0) {
564                 index = 0;
565             } else if (index >= counts) {
566                 index = counts - 1;
567             }
568             setting.current = index;
569             setting.currentMethod.process();
570         }
571     }
572 }

转载于:https://www.cnblogs.com/kardel/archive/2012/07/17/2596595.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值