一、先附上demo

<!doctype html> <html> <head> <meta charset="utf-8"> <title>contenteditable</title> <style> </style> <link href="http://a.tbcdn.cn/apps/tbtx/miiee/css/base.css" rel="stylesheet"> <link href="switchable.css" rel="stylesheet"> <style> /*1002*380圖片切換*/ .w1002-img-switch { position: relative; width: 1002px; height: 380px; overflow: hidden; margin: 50px auto; } .w1002-img-switch .switch-content { width: 100%; height: 100%; } .w1002-img-switch .switch-content a { float: left; display: inline; width: 1002px; height: 100%; } .w1002-img-switch .switch-prev-btn, .w1002-img-switch .switch-next-btn { position: absolute; top: 160px; width: 61px; height: 61px; cursor: pointer; opacity: .3; filter: alpha(opacity=50); background-image: url(http://img01.taobaocdn.com/tps/i1/T1jGOxXqthXXahT_rS-300-150.png); background-repeat: no-repeat; } .w1002-img-switch .switch-prev-btn { left: 0; background-position: -120px 0; } .w1002-img-switch .switch-next-btn { right: 0; background-position: -185px 0; } .w1002-img-switch .switch-prev-btn:hover { transition: opacity .12s linear; opacity: 1; filter: alpha(opacity=100); background-position: -120px -70px; } .w1002-img-switch .switch-next-btn:hover { transition: opacity .12s linear; opacity: 1; filter: alpha(opacity=100); background-position: -185px -70px; } </style> <link href="http://a.tbcdn.cn/apps/tbtx/miiee/css/home.css" rel="stylesheet"> <script src="http://code.jquery.com/jquery-1.10.2.js"></script> </head> <body> <div class="miiee-content"> <div id="first-block"> <div id="first-block-switch" class="switch-img"> <div class="switch-content-wrap"> <ul class="switch-content clearfix"> <li> <a href="http://miiee.taobao.com/themes/theme_133.htm" target="_blank"> <img src="http://gtms01.alicdn.com/tps/i1/T18ITBFmXfXXXKa4be-670-490.jpg" alt="型男奶爸正當紅" title="型男奶爸正當紅"> </a> </li> <li> <a href="http://detail.tmall.com/item.htm?id=35257025329" target="_blank"> <img src="http://gtms04.alicdn.com/tps/i4/T1qtrGFcpbXXXKa4be-670-490.jpg" alt="都贏男裝旗艦店" title="都贏男裝旗艦店"> </a> </li> <li> <a href="http://miiee.taobao.com/themes/theme_130.htm" target="_blank"> <img src="http://gtms01.alicdn.com/tps/i1/T1Od6EFcBaXXXKa4be-670-490.jpg" alt="蜜桃愛語" title="蜜桃愛語"> </a> </li> <li> <a href="http://www.taobao.com/go/app/tbtx/tashuo.php" target="_blank"> <img src="http://gtms01.alicdn.com/tps/i1/T1BvPDFnBcXXXKa4be-670-490.jpg" alt="明星" title="明星"> </a> </li> <li> <a href="http://miiee.taobao.com/themes/theme_131.htm" target="_blank"> <img src="http://gtms01.alicdn.com/tps/i1/T1mR6EFhBbXXXKa4be-670-490.jpg" alt="音樂節穿點不一樣的" title="音樂節穿點不一樣的"> </a> </li> <li> <a href="http://jiuxian.tmall.com/" target="_blank"> <img src="http://gtms03.alicdn.com/tps/i3/T11DLvFedfXXXKa4be-670-490.jpg" alt="酒仙" title="酒仙"> </a> </li> <li> <a href="http://miiee.taobao.com/bargain.htm" target="_blank"> <img src="http://gtms04.alicdn.com/tps/i4/T1tpmVFataXXXKa4be-670-490.jpg" alt="砍你妹" title="砍你妹"> </a> </li> <li> <a href="http://nvren.taobao.com/" target="_blank"> <img src="http://gtms01.alicdn.com/tps/i1/T1ipfHFlpaXXcmcNbe-670-490.png" alt="拍賣" title="淘寶女人"> </a> </li> </ul> </div> <div class="switch-nav"> <span class="ks-active"></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> </div> <a class="prev" href="javascript:void(0)"></a> <a class="next" href="javascript:void(0)"></a> </div> </div> </div> <div class="w1002-img-switch"> <div class="clearfix switch-content"> <a href="" target="_blank"> <img width="1002" height="380" src="http://img.la/green/gif/1002x380"> </a> <a href="" target="_blank"> <img width="1002" height="380" src="http://img.la/01531e/gif/1002x380"> </a> <a href="" target="_blank"> <img width="1002" height="380" src="http://img.la/af8003/gif/1002x380"> </a> <a href="" target="_blank"> <img width="1002" height="380" src="http://img.la/green/gif/1002x380"> </a> <a href="" target="_blank"> <img width="1002" height="380" src="http://img.la/01531e/gif/1002x380"> </a> <a href="" target="_blank"> <img width="1002" height="380" src="http://img.la/af8003/gif/1002x380"> </a> </div> <div class="switch-trigger" style="position: absolute; right: 0; bottom: 15px;"> <span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span> </div> <a class="switch-prev-btn" href="javascript:void(0);"></a> <a class="switch-next-btn" href="javascript:void(0);"></a> </div> <div id="switchable-wrap"> <div class="switchable-content-wrap"> <div class="clearfix switchable-content"> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1okV1FmdbXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1EWd1FnJbXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1WQR0FjBcXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1dvF0FmVeXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1JRN2FdJXXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1S6F2FXhcXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T179FZFkFeXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1s5VYFetgXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1UyF0FjJfXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1PXB3FltXXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1tvV0FgdeXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T1nZJ3FcRXXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T13stZFnJfXXb1upjX.jpg"> </div> <div> <img width="180" height="180" src="http://img01.taobaocdn.com/bao/uploaded/i1/T11q43FepaXXb1upjX.jpg"> </div> </div> </div> <div class="prev-btn"></div> <div class="next-btn"></div> </div> <script> /* * jQuery.switchable(config) 圖片輪播插件 * @param: {Object} 配置參數對象 * @author: 博客園華子yjh */ jQuery.extend({ /* 圖片輪播 yjh update 2013/11/25 config = { wrapSelector: 外圍選擇器, contentSelector: 內容選擇器, prevBtnSelector: 觸發器(上一個), nextBtnSelector: 觸發器(下一個), triggerSelector: '.switch-trigger', 觸發器 autoPlay: true, 自動輪播 delay: 3000 延遲時間, interval: 3000 間隔時間, duration: 400 動畫時間 } */ switchable: function(config) { var timeoutId, $wrap = $( config.wrapSelector ), $content = $wrap.find( config.contentSelector ), $contentParent = $content.parent().css({ position: 'relative' }), $panels = $content.children(), len = $panels.length, // 單個面板盒子寬度 singlePanelBoxWidth = $panels.eq(0).outerWidth(true), // 視口寬度 viewportWidth = $contentParent.width(), // 視口中的面板個數 viewportPanelCount = Math.ceil(viewportWidth/singlePanelBoxWidth), // 視口中所有面板盒子寬度的總和 // 即: 動畫過度的像素 viewSize = /*config.viewSize || */singlePanelBoxWidth*viewportPanelCount, // 所有面板占用的視口個數 viewportCount = Math.ceil(len/viewportPanelCount), // 所有面板占用的視口個數 * viewSize totalViewSize = viewportCount*viewSize; if ( len <= viewportPanelCount ) { $( config.prevBtnSelector ).remove(); $( config.nextBtnSelector ).remove(); return; } $content.css({ width: totalViewSize + 'px', position: 'absolute' }); var leftVal, startState = true, endState = false; function dynamicUpdate() { leftVal = Math.abs( parseInt($content.css('left'), 10) ) || 0; if ( leftVal < viewSize ) { startState = true; endState = false; } else if ( (leftVal + viewSize) >= totalViewSize ) { endState = true; startState = false; } else { startState = false; endState = false; } } // 激活觸發器的狀態 function activateTrigger(arg) { var leftVal = arg; var idx = Math.ceil(leftVal/viewSize); if ( idx < 0 ) { idx = idx*(-1); // 需將負數轉為正數 } if ( idx >= viewportCount ) { idx = 0; } $triggers.eq(idx).addClass('trigger-active ks-active').siblings().removeClass('trigger-active ks-active'); } function nextEvent() { var tempVal; if ( $content.filter(':animated').length === 0 ) { dynamicUpdate(); tempVal = leftVal + viewSize; if ( !endState ) { $content.animate({ left: -tempVal + 'px'}, config.duration || 400, 'swing', function(){ if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } else { var $outPanels = $panels.filter(function(idx){ return idx < len-viewportPanelCount }); $outPanels.css({ position: 'relative', left: tempVal + 'px' }); $content.animate({ left: -tempVal + 'px'}, config.duration || 400, 'swing', function(){ $outPanels.removeAttr('style'); $content.css({ left: 0 }); if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } } } function prevEvent() { var tempVal; if ( $content.filter(':animated').length === 0 ) { dynamicUpdate(); tempVal = -leftVal + viewSize; if ( !startState ) { $content.animate({ left: tempVal + 'px'}, config.duration || 400, 'swing', function(){ if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } else { tempVal = -totalViewSize + viewSize; var $outPanels = $panels.filter(function(idx){ return idx >= viewportPanelCount }); $outPanels.css({ position: 'relative', left: -totalViewSize + 'px' }); $content.animate({ left: viewSize + 'px'}, config.duration || 400, 'swing', function(){ $outPanels.removeAttr('style'); $content.css({ left: tempVal + 'px' }); if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } } } function autoSwitch(){ clearTimeout(timeoutId); // fix two timeoutId execute timeoutId = setTimeout(function callee(){ nextEvent(); timeoutId = setTimeout(callee, config.interval || 3000); }, config.delay || 3000); } function wrapEventHandle(e){ if ( e.type === 'mouseenter' ) { clearTimeout(timeoutId); } else if ( e.type === 'mouseleave' ) { if ( config.autoPlay ) { autoSwitch(); } } } if ( config.autoPlay || false ) { autoSwitch(); // 自動輪播 $wrap.bind('mouseenter mouseleave', wrapEventHandle); } $( config.nextBtnSelector ).bind('click', function(){ nextEvent(); }); $( config.prevBtnSelector ).bind('click', function(){ prevEvent(); }); // 處理觸發器 if ( config.triggerSelector ) { var $triggers = $(config.triggerSelector).children().addClass('switch-item-trigger'); $(document).delegate(config.wrapSelector + ' ' + '.switch-item-trigger', 'mouseenter click', triggerEventHandle); } function triggerEventHandle(e){ var idx = $triggers.index( $(e.target) ); if ( idx < viewportCount ) { var tmpVal = viewSize*idx; if ( $content.filter(':animated').length === 0 ) { $content.animate({ left: '-' + tmpVal + 'px'}, config.duration || 400, 'swing'); if ( e.type === 'mouseenter' || e.type === 'click' ) { $triggers.eq(idx).addClass('trigger-active ks-active').siblings().removeClass('trigger-active ks-active'); } } } } return jQuery; } }); $(function(){ $.switchable({ wrapSelector: '#first-block-switch', contentSelector: '.switch-content', prevBtnSelector: '.prev', nextBtnSelector: '.next', triggerSelector: '.switch-nav', autoPlay: true, duration: 300, interval: 3000 }) .switchable({ wrapSelector: '.w1002-img-switch', contentSelector: '.switch-content', prevBtnSelector: '.switch-prev-btn', nextBtnSelector: '.switch-next-btn', autoPlay: true, duration: 300, interval: 4000, triggerSelector: '.switch-trigger' }) .switchable({ wrapSelector: '#switchable-wrap', contentSelector: '.switchable-content', prevBtnSelector: '.prev-btn', nextBtnSelector: '.next-btn', autoPlay: true, duration: 300, interval: 4000, delay: 3000 }); }); </script> </body> </html>
二、實現思路
1、設置面板容器元素的left屬性值,觸發下一輪輪播,將left - viewSize(大於等於面板寬度),當前為最后一輪時,將當前顯示的面板子元素的兄弟元素設置相對定位,並設置相應的位置,支持下一輪輪播循環;觸發上一輪輪播,將left + viewSize,當前為首輪時,同理將當前顯示的面板子元素的兄弟元素設置相對定位,並設置相應的位置,支持下上一輪輪播循環;
2、如果當前面板顯示的元素只有一個時,允許有觸發器,監聽mouseenter事件,並顯示對應的面板子元素;
3、激活面板子元素所對應的當前觸發器的狀態,這一部分在動畫完成后實現,當前觸發器的className為固定trigger-active ks-active,當然也可以自行配置;
4、當鼠標移動在整個外圍容器中時,將清除自動輪播的定時器,離開時重新執行定時器,支持自動輪播,自動輪播的延遲時間為可配置項delay,其他配置項interval為自動輪播
的間隔時間,duration為動畫時間,autoplay默認為false。
三、源碼
/** * jQuery.switchable(config) 圖片輪播插件 * @param: {Object} 配置參數對象 * @author: 博客園華子yjh * update-time: 2013/12/12 */ jQuery.extend({ /** 圖片輪播 config = { wrapSelector: 外圍選擇器, contentSelector: 內容選擇器, prevBtnSelector: 觸發器(上一個), nextBtnSelector: 觸發器(下一個), triggerSelector: '.switch-trigger', 觸發器 autoPlay: true, 自動輪播 delay: 3000 延遲時間, interval: 3000 間隔時間, duration: 400 動畫時間, handleImgLoad: 用於懶加載的事件處理函數 } */ switchable: function(config) { var timeoutId, $wrap = $( config.wrapSelector ), $content = $wrap.find( config.contentSelector ), $contentParent = $content.parent().css({ position: 'relative' }), $panels = $content.children(), len = $panels.length, // 單個面板盒子寬度 singlePanelBoxWidth = $panels.eq(0).outerWidth(true), // 視口寬度 viewportWidth = $contentParent.width(), // 視口中的面板個數 viewportPanelCount = Math.ceil(viewportWidth/singlePanelBoxWidth), // 視口中所有面板盒子寬度的總和 // 即: 動畫過度的像素 viewSize = /*config.viewSize || */singlePanelBoxWidth*viewportPanelCount, // 所有面板占用的視口個數 viewportCount = Math.ceil(len/viewportPanelCount), // 所有面板占用的視口個數 * viewSize totalViewSize = viewportCount*viewSize; if ( len <= viewportPanelCount ) { $( config.prevBtnSelector ).remove(); $( config.nextBtnSelector ).remove(); return; } $content.css({ width: totalViewSize + 'px', position: 'absolute' }); var leftVal, startState = true, endState = false; function dynamicUpdate() { leftVal = Math.abs( parseInt($content.css('left'), 10) ) || 0; if ( leftVal < viewSize ) { startState = true; endState = false; } else if ( (leftVal + viewSize) >= totalViewSize ) { endState = true; startState = false; } else { startState = false; endState = false; } } // 預加載圖片處理 function handleImgLoad(tempVal, e) { if ( config.handleImgLoad ) { if ( e && $(e.target).length > 0 && $(e.target).is(config.prevBtnSelector) ) { var idx = Math.abs( Math.ceil(tempVal/singlePanelBoxWidth) ); if (startState) { idx = len - 1; } } else { // 默認為next idx = Math.abs( Math.ceil(tempVal/singlePanelBoxWidth) ); if (endState) { idx = 0; } } config.handleImgLoad(idx); } } // 激活觸發器的狀態 function activateTrigger(arg) { var leftVal = arg; var idx = Math.ceil(leftVal/viewSize); if ( idx < 0 ) { idx = idx*(-1); // 需將負數轉為正數 } if ( idx >= viewportCount ) { idx = 0; } $triggers.eq(idx).addClass('trigger-active ks-active').siblings().removeClass('trigger-active ks-active'); } function nextEvent(e) { var event, tempVal, triggerCls; if ( $content.filter(':animated').length === 0 ) { dynamicUpdate(); tempVal = leftVal + viewSize; handleImgLoad(tempVal, e); // 圖片預加載 if ( !endState ) { $content.animate({ left: -tempVal + 'px'}, config.duration || 400, 'swing', function(){ if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } else { var $outPanels = $panels.filter(function(idx){ return idx < len-viewportPanelCount }); $outPanels.css({ position: 'relative', left: tempVal + 'px' }); $content.animate({ left: -tempVal + 'px'}, config.duration || 400, 'swing', function(){ $outPanels.removeAttr('style'); $content.css({ left: 0 }); if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } } } function prevEvent(e) { var tempVal; if ( $content.filter(':animated').length === 0 ) { dynamicUpdate(); tempVal = -leftVal + viewSize; handleImgLoad(tempVal, e); // 圖片預加載 if ( !startState ) { $content.animate({ left: tempVal + 'px'}, config.duration || 400, 'swing', function(){ if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } else { tempVal = -totalViewSize + viewSize; var $outPanels = $panels.filter(function(idx){ return idx >= viewportPanelCount }); $outPanels.css({ position: 'relative', left: -totalViewSize + 'px' }); $content.animate({ left: viewSize + 'px'}, config.duration || 400, 'swing', function(){ $outPanels.removeAttr('style'); $content.css({ left: tempVal + 'px' }); if ( config.triggerSelector ) { activateTrigger(tempVal); } }); } } } function autoSwitch(){ clearTimeout(timeoutId); // fix two timeoutId execute timeoutId = setTimeout(function callee(){ nextEvent(); timeoutId = setTimeout(callee, config.interval || 3000); }, config.delay || 3000); } function wrapEventHandle(e){ if ( e.type === 'mouseenter' ) { clearTimeout(timeoutId); } else if ( e.type === 'mouseleave' ) { if ( config.autoPlay ) { autoSwitch(); } } } if ( config.autoPlay || false ) { autoSwitch(); // 自動輪播 $wrap.bind('mouseenter mouseleave', wrapEventHandle); } $( config.nextBtnSelector ).bind('click', nextEvent); $( config.prevBtnSelector ).bind('click', prevEvent); // 處理觸發器 if ( config.triggerSelector ) { var $triggers = $(config.triggerSelector).children().addClass('switch-item-trigger'); $(document).delegate(config.wrapSelector + ' ' + '.switch-item-trigger', 'mouseenter click', triggerEventHandle); } function triggerEventHandle(e){ var idx = $triggers.index( $(e.target) ); if ( idx < viewportCount ) { var tempVal = viewSize*idx; config.handleImgLoad(idx); if ( $content.filter(':animated').length === 0 ) { $content.animate({ left: '-' + tempVal + 'px'}, config.duration || 400, 'swing'); if ( e.type === 'mouseenter' || e.type === 'click' ) { $triggers.eq(idx).addClass('trigger-active ks-active').siblings().removeClass('trigger-active ks-active'); } } } } return jQuery; } });
PS: 實現的過程操作均在動畫完成之后執行的,就是用戶必須在輪播完后,進行下一次的上下輪播,這也算是我的實現瓶勁,望高手多多指教
轉載請注明出處博客園,華子yjh。