面板支持單個,多個元素的jQuery圖片輪播插件


一、先附上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>
View Code

二、實現思路

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM