前几天决定写一个基于jQuery的移动端大跨度滑动插件,大致可以设置的参数有:
num: 3, //Wrap内子元素个数, >0 index: 0, //初始化索引值 initX: 10, //X轴滑动大于此属性触发事件 U.px limitX: 30, //X轴滑动大于此属性触发滑动 U.px limitY: 70, //Y轴滑动大于些属性禁止滑动 U.px speed: 300, //滚屏速度, 值越大越慢 U.ms [>=0 && <=1] edgeSlideVal: 15, //边缘滑动最大距离 U.px [>0] perSlide: 1, //每次滑动元素数量 isScreen: true, //每次滑动 [屏 || 元素]; 为true时,perSlide失效; 为false时,isSplice失效 isEqual: false, //Wrap内子元素是否等宽; 为false时,num、isPerSlideLimit、equalKeepDir 失效 equalKeepDir: "left", //元素等宽时贴靠方向 [left || right || false:不限制] isSecSlide: true, //isEqual:false && perSlide:1 子元素宽度超出Wrap宽度时是否允许二次滑动 autoplay: false, //自动滑动时间; 为false时不自动滑动 U.ms [应大于speed值] isLoop: false, //是否自动循环; 为true时,isEdgeSlide失效,isScreen将强制为true dir: true, //自动循环方向 [true:左 || false:右] isEdgeSlide: false, //是否允许边缘滑动 isSplice: true, //是否前后拼接 isGPURender: true, //是否使用GPU渲染 isPerSlideLimit: true, //每次滑动元素数量是否限制; 为true时,值必须<=num值 isDot: true, //是否显示数量点 callback: null, //回调函数
废话不多说,直接上码。
html { font-size:100px;} body { font-size:12px;} /*mSlide*/ .clr:before, .clr:after { display:block; content:""; clear:both; height:0; visibility:hidden; font-size:0;} .mSlide { width:100%; overflow:hidden;} .mSlide ul { overflow:hidden; opacity:1;} .mSlide ul li { display:block; float:left;} .mSlide ul figure { width:100%; height:100%; background:no-repeat center center; background-size:cover; text-align:center; line-height:2rem; font-size:.3rem; font-weight:bold; color:#f90; text-shadow:-1px 2px 0 rgba(0,0,0,.7);} .mSlide .dot { position:absolute; left:0; bottom:0; width:100%; height:.12rem; text-align:center; line-height:1;} .mSlide .dot i { display:inline-block; width:6px; height:6px; margin:0 .02rem; border-radius:50%; background:rgba(0,0,0,.4); vertical-align:top; line-height:1;} .mSlide .dot i.on { background:rgba(255,255,255,.7);} /*Test*/ .mSlide ul li { width:100px; height:1.5rem;} .mSlide ul li.li2 { width:150px; height:1.5rem;} .mSlide ul li.li3 { width:80px; height:1.5rem;} .mSlide ul li.li4 { width:500px; height:1.5rem;} .mSlide ul li.li6 { width:320px; height:1.5rem;}
CSS部分
<div class="mSlide"> <ul class="clr"> <li><figure style="background-image:url(images/1.jpg);">1</figure></li> <li class="li2"><figure style="background-image:url(images/2.jpg);">2</figure></li> <li class="li3"><figure style="background-image:url(images/3.jpg);">3</figure></li> <li class="li4"><figure style="background-image:url(images/4.jpg);">4</figure></li> <li class="li2"><figure style="background-image:url(images/5.jpg);">5</figure></li> <li><figure style="background-image:url(images/6.jpg);">6</figure></li> <li class="li6"><figure style="background-image:url(images/7.jpg);">7</figure></li> <li class="li3"><figure style="background-image:url(images/8.jpg);">8</figure></li> </ul> </div>
/*** * jQuery plugin mSlide() * Function : 移动端左右滑动mSlide 2.0 * Version : 2.0 * Author : Cymmint * Date : 2015-08-31 22:10 * 撸了几天终于把基本功能实现,插件肯定还有很多BUG,欢迎指正和建议 */ ;(function($) { $.fn.mSlide = function(opts) { var define = { num: 3, //Wrap内子元素个数, >0 index: 0, //初始化索引值 initX: 10, //X轴滑动大于此属性触发事件 U.px limitX: 30, //X轴滑动大于此属性触发滑动 U.px limitY: 70, //Y轴滑动大于些属性禁止滑动 U.px speed: 300, //滚屏速度, 值越大越慢 U.ms [>=0 && <=1] edgeSlideVal: 15, //边缘滑动最大距离 U.px [>0] perSlide: 1, //每次滑动元素数量 isScreen: true, //每次滑动 [屏 || 元素]; 为true时,perSlide失效; 为false时,isSplice失效 isEqual: false, //Wrap内子元素是否等宽; 为false时,num、isPerSlideLimit、equalKeepDir 失效 equalKeepDir: "left", //元素等宽时贴靠方向 [left || right || false:不限制] isSecSlide: true, //isEqual:false && perSlide:1 子元素宽度超出Wrap宽度时是否允许二次滑动 autoplay: false, //自动滑动时间; 为false时不自动滑动 U.ms [应大于speed值] isLoop: false, //是否自动循环; 为true时,isEdgeSlide失效,isScreen将强制为true dir: true, //自动循环方向 [true:左 || false:右] isEdgeSlide: false, //是否允许边缘滑动 isSplice: true, //是否前后拼接 isGPURender: true, //是否使用GPU渲染 isPerSlideLimit: true, //每次滑动元素数量是否限制; 为true时,值必须<=num值 isDot: true, //是否显示数量点 callback: null, //回调函数 }, opts = $.extend({}, define, opts); //配置 var Config = { param: function() { opts.num = opts.num < 1 ? 1 : opts.num; //Wrap内子元素数量 opts.speed = isNaN(opts.speed) || opts.speed <= 0 ? 300 : opts.speed; //滚屏速度 opts.edgeSlideVal = isNaN(opts.edgeSlideVal) || opts.edgeSlideVal <= 0 ? 0 : opts.edgeSlideVal; //边缘滑动距离 opts.isScreen = opts.isLoop ? true : opts.isScreen; //每次滑动屏 opts.pre = Config.prefix().lowercase; //CSS3前缀 opts.isSecSlide = opts.isSecSlide && !opts.isScreen && opts.perSlide == 1 ? true : false; //二次滑动 opts.autoplay = opts.autoplay ? isNaN(opts.autoplay) || opts.autoplay < opts.speed ? opts.speed : opts.autoplay : false; //自动滑动 opts.isLoop = opts.isLoop && opts.autoplay >= opts.speed ? true : false; //自动循环 opts.isEdgeSlide = !opts.isLoop && opts.isEdgeSlide ? true : false; //边缘滑动 opts.isSplice = opts.isScreen && opts.isSplice ? true : false; //前后拼接 opts.transitionEnd = "transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd msTransitionEnd"; //动画完成事件名 opts.equalKeepDir = opts.isEqual && opts.equalKeepDir ? opts.equalKeepDir.toLowerCase() == "left" ? "left" : "right" : false; //元素等宽时贴靠方向 if(opts.isEqual && opts.isPerSlideLimit) { //每次滑动元素数量限制 opts.perSlide = opts.perSlide > opts.num ? opts.num : opts.perSlide < 1 ? 1 : opts.perSlide; } }, prefix: function() { //获取CSS3前缀 var styles = window.getComputedStyle(document.documentElement, ""), pre = (Array.prototype.slice.call(styles).join("").match(/-(moz|webkit|ms)-/) || (styles.OLink === "" && ["", "o"]))[1], dom = ("WebKit|Moz|MS|O").match(new RegExp("(" + pre + ")", "i"))[1]; return { dom: dom, lowercase: pre, css: "-" + pre + "-", js: pre[0].toUpperCase() + pre.substr(1) }; }, width: function(Sub) { var aryVal = [], len = Sub.len; for(var i=0; i<len; i++) { if(opts.isEqual) { aryVal.push(Sub.width / opts.num); } else { aryVal.push(Sub.child.eq(i).innerWidth()); } } return aryVal; }, offset: function(Sub) { var aryVal = [], len = Sub.len; for(var i=0; i<len; i++) { aryVal.push(Sub.child.eq(i).offset().left); } return aryVal; }, sum: function(Sub) { var sum = 0, len = Sub.len; if(opts.isEqual) { sum = Sub.width / opts.num * Sub.len; } else { for(var i=0; i<len; i++) { sum += Sub.aryChildWidth[i]; } } return sum; }, leftDup: function(Sub) { var sum = 0, len = Sub.len - 1; for(var i=len; i>=0; i--) { sum += Sub.aryChildWidth[i]; if(sum >= Sub.width) { break; } } len = i; for(i=Sub.len-1; i>=len; i--) { Sub.child.eq(i).clone().addClass("dup").prependTo(Sub.box); } return sum; }, rightDup: function(Sub) { var sum = 0, len = Sub.len; for(var i=0; i<len; i++) { sum += Sub.aryChildWidth[i]; if(sum >= Sub.width) { break; } } len = i; i = Sub.len - 1; for(i=0; i<=len; i++) { Sub.child.eq(i).clone().addClass("dup").appendTo(Sub.box); } return sum; }, edge: function(Sub) { Sub.box.css({"transition-duration": "0ms", "-webkit-transition-duration": "0ms"}); if(Sub.edge && Sub.loop) { Methods.translate(Sub, -(Sub.offset + Sub.beforeHideWidth), null); Sub.edge = false; } } }; Config.param(); var Methods = { translate: function (Sub, d, anim) { var anim = anim == null ? "0ms" : isNaN(anim) ? "0.2s" : (anim) + "ms", tran = opts.isGPURender ? "translate3d(" + d + "px, 0, 0)" : "translate(" + d + "px, 0)", attr = {}; attr["transitionDuration"] = anim; attr["transform"] = tran; attr[opts.pre + "TransitionDuration"] = anim; attr[opts.pre + "Transform"] = tran; Sub.box.css(attr); }, slider: function(_this, Sub) { var X, Y, dX, dY, isChange; _this.on({ "touchstart": function (e) { var ev = e.originalEvent; ev.stopPropagation(); if(Sub.hasOwnProperty("clear")) { //清除自动滑动 clearInterval(Sub.clear); } if (ev.targetTouches.length == 1) { var touch = ev.targetTouches[0]; X = touch.pageX; Y = touch.pageY; dX = dY = 0; Sub.box.css({"transition-duration": "0ms", "-webkit-transition-duration": "0ms"}); } }, "touchmove": function (e) { var ev = e.originalEvent; ev.stopPropagation(); if (ev.targetTouches.length == 1) { var touch = ev.targetTouches[0]; dX = touch.pageX - X; dY = touch.pageY - Y; isChange = true; if(Math.abs(dY) < opts.limitY && Math.abs(dX) > opts.initX) { var move = Sub.offset - dX / 2; if(opts.isSplice) { //前后拼接 if(dX < 0 && Sub.offset >= Sub.maxOffset) { //Left Sub.edge = true; } else if(dX > 0 && Sub.offset <= 0) { //Right Sub.edge = true; } } else { if(opts.isEdgeSlide) { //边缘滑动 if(dX < 0 && Sub.offset >= Sub.maxOffset) { //Left move = move > Sub.maxOffset + opts.edgeSlideVal ? Sub.maxOffset + opts.edgeSlideVal : move; } else if(dX > 0 && Sub.offset <= 0) { //Right move = -move > opts.edgeSlideVal ? -opts.edgeSlideVal : move; } } else { if(dX < 0 && Sub.offset >= Sub.maxOffset) { //Left move = Sub.maxOffset; isChange = false; } else if(dX > 0 && Sub.offset <= 0) { //Right move = 0; isChange = false; } } } if(isChange) { Methods.translate(Sub, -(move + Sub.beforeHideWidth), null); } } } }, "touchend": function (e) { var ev = e.originalEvent, offset; ev.stopPropagation(); if(isChange) { if(Math.abs(dY) < opts.limitY && Math.abs(dX) > opts.limitX) { if(dX < 0) { //Left offset = Methods.offset(Sub, true); } else { //Right offset = Methods.offset(Sub, false); } } else { offset = -(Sub.beforeHideWidth + Sub.offset); } Methods.translate(Sub, offset, opts.speed); } if(Sub.loop || (opts.autoplay >= opts.speed && !Sub.edge)) { //自动滑动 Sub.clear = setInterval(function() { Methods.auto(Sub);}, opts.autoplay); } } }); }, offset: function(Sub, dir) { var offset = null, mark = true; if(Sub.offset == null) { //初始 [第一次调用] offset = Sub.aryChildOffset[Sub.idx]; offset = offset >= Sub.maxOffset ? Sub.maxOffset : offset; } else { if(opts.isScreen) { //按屏滑动 offset = Sub.offset; if(dir) { if(opts.isSplice && Sub.offset >= Sub.maxOffset) { offset = Sub.beforeHideWidth + Sub.maxOffset + Sub.width; Sub.offset = 0; Sub.edge = true; mark = false; } else { offset += Sub.width; offset = offset >= Sub.maxOffset ? Sub.maxOffset : offset; } } else { if(opts.isSplice && Sub.offset <= 0) { offset = Sub.beforeHideWidth - Sub.width; Sub.offset = Sub.maxOffset; Sub.edge = true; mark = false; } else { offset -= Sub.width; offset = offset <= 0 ? 0 : offset; } } if(offset == 0 || offset == Sub.maxOffset) { Sub.edge = true; } } else { //按元素滑动 if(dir) { //Left if(Math.floor(Sub.offset) < Math.floor(Sub.maxOffset)) { if(opts.isSecSlide && Sub.aryChildWidth[Sub.idx] > Sub.width) { //同子元素二次滑动 if(Sub.offset == Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.width) { Sub.idx = Sub.idx + opts.perSlide >= Sub.len - 1 ? Sub.len - 1 : Sub.idx + opts.perSlide; offset = Sub.aryChildOffset[Sub.idx]; } else { if(Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.offset <= Sub.width * 2) { offset = Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.width; } else { offset = Sub.offset + Sub.width; } } } else { Sub.idx = Sub.idx + opts.perSlide >= Sub.len - 1 ? Sub.len - 1 : Sub.idx + opts.perSlide; if(opts.equalKeepDir == "right") { //元素等宽停靠方向 if(Sub.idx <= opts.num) { offset = Sub.aryChildOffset[Sub.idx]; Sub.keepDir = true; } else { if(Sub.keepDir) { Sub.keepDir = false; Sub.idx = Sub.idx + opts.num - 1 >= Sub.len - 1 ? Sub.len - 1 : Sub.idx + opts.num -1; } offset = Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.width; } } else { offset = Sub.aryChildOffset[Sub.idx]; } } offset = offset >= Sub.maxOffset ? Sub.maxOffset : offset; if(offset == Sub.maxOffset) { Sub.idx = Sub.len - 1; } } else { offset = Sub.maxOffset; Sub.idx = Sub.len - 1; Sub.edge = true; mark = false; } } else { //Right if(Sub.offset > 0) { if(opts.isSecSlide && Sub.aryChildWidth[Sub.idx] > Sub.width) { //同子元素二次滑动 if(Sub.offset == Sub.aryChildOffset[Sub.idx]) { Sub.idx = Sub.idx - opts.perSlide <= 0 ? 0 : Sub.idx - opts.perSlide; offset = Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.width; } else { if(Sub.offset - Sub.width <= Sub.aryChildOffset[Sub.idx]) { offset = Sub.aryChildOffset[Sub.idx]; } else { offset = Sub.offset - Sub.width; } } } else { Sub.idx = Sub.idx - opts.perSlide <= 0 ? 0 : Sub.idx - opts.perSlide; if(opts.equalKeepDir == "left") { //元素等宽停靠方向 if(Sub.idx >= Sub.len - opts.num) { offset = Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.width; Sub.keepDir = true; } else { if(Sub.keepDir) { Sub.keepDir = false; Sub.idx = Sub.idx - opts.num + 1 <= 0 ? 0 : Sub.idx - opts.num + 1; } offset = Sub.aryChildOffset[Sub.idx]; } } else { offset = Sub.aryChildOffset[Sub.idx] + Sub.aryChildWidth[Sub.idx] - Sub.width; } } offset = offset <= 0 ? 0 : offset; if(offset == 0) { Sub.idx = 0; } } else { offset = 0; Sub.idx = 0; Sub.edge = true; mark = false; } } } } if(mark) { Sub.offset = offset; offset = offset + Sub.beforeHideWidth; } if(opts.isDot) { //Dot切换 Methods.dotSite(Sub); } return -offset; }, dotSite: function(Sub) { var beg = Sub.offset, end = Sub.offset + Sub.width - 1, offset; Sub.dot.removeClass("on"); for(var i=0; i<=Sub.len; i++) { offset = Math.floor(Sub.aryChildOffset[i]); if((offset >= beg && offset <= end) || (offset + Sub.aryChildWidth[i] > beg && offset + Sub.aryChildWidth[i] < end)) { Sub.dot.eq(i).addClass("on"); } } if(Sub.aryChildWidth[Sub.idx] > Sub.width) { Sub.dot.eq(Sub.idx).addClass("on"); } }, auto: function(Sub) { var offset = Methods.offset(Sub, opts.dir); Methods.translate(Sub, offset, opts.speed); if(!Sub.loop && Sub.edge) { clearInterval(Sub.clear); } }, main: function(Sub) { var offset = Methods.offset(Sub, true); Methods.translate(Sub, offset, null); //Move Sub.box.on(opts.transitionEnd, function(){ //重置动画|时间 Config.edge(Sub); }); if(opts.autoplay >= opts.speed) { //自动滑动 Sub.clear = setInterval(function() { Methods.auto(Sub);}, opts.autoplay); } }, init: function(_this) { var Sub = {}, htm = ""; Sub.box = _this.find("ul"); Sub.width = _this.innerWidth(); Sub.child = Sub.box.children(); Sub.len = Sub.child.length; Sub.idx = opts.index >= Sub.len ? 0 : opts.index; if(opts.isEqual) { //子元素等宽 Sub.child.css({"width": Sub.width / opts.num}); } Sub.beforeHideWidth = 0; //过渡宽度 Sub.afterHideWidth = 0; Sub.aryChildWidth = Config.width(Sub); //各子元素Width Sub.chlidSumWidth = Config.sum(Sub); Sub.box.css({"width": Sub.chlidSumWidth}); Sub.aryChildOffset = Config.offset(Sub); //各子元素Offset Sub.maxOffset = Sub.chlidSumWidth - Sub.width <= 0 ? 0 : Sub.chlidSumWidth - Sub.width; Sub.offset = null; //当前偏移 Sub.edge = false; //边缘 Sub.loop = opts.isLoop && Sub.chlidSumWidth >= Sub.width; //条件组合是否满足自动循环 if(opts.isSplice) { //前后拼接 Sub.beforeHideWidth = Config.leftDup(Sub);; Sub.afterHideWidth = Config.rightDup(Sub);; Sub.box.css({"width": Sub.chlidSumWidth + Sub.beforeHideWidth + Sub.afterHideWidth}); } if(opts.isDot) { //Dot _this.css({"position": "relative"}); htm = ‘<div class="dot">‘; for(var i=0; i<Sub.len; i++) { htm += ‘<i></i>‘; } htm += ‘</div>‘; _this.append(htm); Sub.dot = _this.find(".dot").children(); } Methods.main(Sub); //Slide Methods.slider(_this, Sub); if(typeof opts.callback == "function") { //函数回调 opts.callback.call(); } } }; return this.each(function(i) { Methods.init($(this)); }); } })(jQuery);
调用插件
$(function() { $("div.mSlide").mSlide({ num: 1, index: 5, perSlide: 1, edgeSlideVal: 50, equalKeepDir: false, isDot: true, isScreen: false, isEdgeSlide: true, isSecSlide: true, isSplice: false, isEqual: false, isDot: true, isLoop: false, autoplay: false, dir: false }); });
时间: 2024-11-02 23:23:30