Featured image of post jQuery - Swiper multi row (다중 행) 정렬 문제 해결

jQuery - Swiper multi row (다중 행) 정렬 문제 해결

Swiper 슬라이드의 다중 행 정렬 수정과 loop 옵션 추가를 위한 코드 예제입니다.

다중 행으로 정렬된 이미지 슬라이드를 만들기 위해 slidesPerColumn 과 slidesPerColumnFill 옵션을 사용했는데, 의도한 순서와 다르게 정렬되는 문제가 발생했다. (최신버전은 Grid)
예를 들어, 첫 번째 페이지에서는 [1, 2, 3, 4, 5, 6], 두 번째 페이지에서는 [7, 8, 9, 10, 11, 12] 순서로 나와야 하는데 아래 사진과 같이 정렬되었다.

Swiper 다중행 옵션 정렬 오류
해당 문제를 해결하기 위해 1페이지에서 보이는 슬라이드 수만큼 swiper-slide 클래스로 그룹화하고, 그룹 안의 리스트를 CSS로 원하는 순서대로 정렬했다.

HTML

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<div class="slider">
    <div class="inner">
        <div class="swiper-wrapper">
            <div class="list">slider1</div>
            <div class="list">slider2</div>
            <div class="list">slider3</div>
            <div class="list">slider4</div>
            <div class="list">slider5</div>
            <div class="list">slider6</div>
            <div class="list">slider7</div>
            <div class="list">slider8</div>
            <div class="list">slider9</div>
            <div class="list">slider10</div>
            <div class="list">slider11</div>
            <div class="list">slider12</div>
        </div>
    </div>
    <div class="swiper-prev">이전</div>
    <div class="swiper-next">다음</div>
</div>

list 클래스명을 가진 요소를 swiper-slide 클래스로 그룹화할 예정이다.

CSS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
* {margin: 0;padding: 0;box-sizing: border-box;}
ul, li {list-style: none;}

.slider {position: relative;max-width: 1180px;margin: 20px auto 0;padding: 0 50px;}
.slider .inner {overflow: hidden;margin-right: -1.333%;}
.slider .swiper-slide {display:flex;flex-wrap:wrap;}
.slider .list {width: 32%;height: 150px;margin: 1% 1.333% 1% 0;background: #8ab4f8;font-size: 20px;line-height: 150px;text-align: center;}
.slider .swiper-prev, .slider .swiper-next {position: absolute;top: 50%;width: 35px;height: 35px;background:url('images/arrow.png') center center no-repeat;background-size: cover;text-indent: -999em;cursor: pointer;font-size: 0;}
.slider .swiper-prev {left: 0;transform: rotateY(180deg) translate(0,-50%);}
.slider .swiper-next {right:0;transform: translate(0,-50%);}

@media (max-width: 768px) {
    .slider .inner {margin-right: -2%;}
    .slider .list{width: 48%;margin-right: 2%;}
}

JS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
$(document).ready(function() {
    slideAct();
})

function slideAct() {
    var view = 0; //보이는 슬라이드 개수
    var realInx = 0; //현재 페이지
    var swiper = undefined;

    //디바이스 체크
    var winWChk = '';
    $(window).on('load resize', function() {
        var winW = window.innerWidth;
        if (winWChk != 'mo' && winW <= 768) { //모바일 버전으로 전환할 때
            slideList()
            winWChk = 'mo';
        }
        if (winWChk != 'pc' && winW >= 769) { //PC 버전으로 전환할 때
            slideList()
            winWChk = 'pc';
        }
    })

    function slideList() {
        //리스트 초기화
        if ($('.slider .list').parent().hasClass('swiper-slide')) {
            $('.slider .swiper-slide-duplicate').remove();
            $('.slider .list').unwrap('swiper-slide');
        }

        //보이는 슬라이드 개수 설정
        if (window.innerWidth > 768) { //PC 버전
            view = 6;
        } else { //mobile 버전
            view = 2;
        }

        //리스트 그룹 생성 (swiper-slide element 추가)
        var num = 0;
        $('.slider').find('.list').each(function(i) {
            $(this).addClass('list' + (Math.floor((i + view) / view)));
            num = Math.floor((i + view) / view)
        }).promise().done(function() {
            for (var i = 1; i < num + 1; i++) {
                $('.slider').find('.list' + i + '').wrapAll('<div class="swiper-slide"></div>');
                $('.slider').find('.list' + i + '').removeClass('list' + i + '');
            }
        });

        sliderStart()
    }

    //슬라이드 시작
    function sliderStart() {
        //슬라이드 초기화
        if (swiper != undefined) {
            swiper.destroy();
            swiper == undefined;
        }

        //슬라이드 실행
        swiper = new Swiper('.slider .inner', {
            slidesPerView: 1,
            initialSlide: Math.floor(realInx / view),
            resistanceRatio: 0,
            loop: true,
            navigation: {
                nextEl: $('.slider').find('.swiper-next')[0],
                prevEl: $('.slider').find('.swiper-prev')[0],
            },
            on: {
                slideChange: function() {
                    realInx = this.realIndex * view
                }
            },
        });
    }
}

주로 반응형 홈페이지 작업을 하기 때문에, 모바일까지 고려하여 view 변수를 사용하여 디바이스별로 1페이지당 슬라이드 개수를 설정했다. 그리고 list 클래스의 총개수를 view 변숫값으로 나누어 각 list 클래스에 해당 값을 추가하고, 같은 index 값을 가진 list 클래스 상위에 wrapAll() 메서드로 swiper-slide 클래스 요소를 추가하여 슬라이드 그룹화를 구현했다.

리사이즈 이벤트가 실행되면 Swiper와 swiper-slide 클래스 요소를 모두 삭제하여 초기화하고, 슬라이드를 다시 불러왔다.
이때, 첫 페이지로 이동되는 문제를 해결하기 위해 현재 페이지의 첫 번째 슬라이드 index 값을 계산하여 realInx 변수에 담고, initialSlide 매개변수를 사용하여 현재 페이지로 다시 이동했다.

그룹화 방법으로 구현한 슬라이드는 정렬 문제를 해결할 뿐만 아니라, 호환되지 않는 loop 옵션도 함께 사용할 수 있다.

JS (each문 추가)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
$(document).ready(function() {
    slideAct();
})

function slideAct() {
    var view = 0; //보이는 슬라이드 개수
    var realInx = [] //현재 페이지
    var swiperArr = [] //슬라이드 배열

    //슬라이드 배열 생성
    $(".slider").each(function(index) {
        realInx.push(0);
        swiperArr.push(undefined);
    })

    //디바이스 체크
    var winWChk = ''
    $(window).on('load resize', function() {
        var winW = window.innerWidth;
        if (winWChk != 'mo' && winW <= 768) { //모바일 버전으로 전환할 때
            slideList()
            winWChk = 'mo';
        }
        if (winWChk != 'pc' && winW >= 769) { //PC 버전으로 전환할 때
            slideList()
            winWChk = 'pc';
        }
    })

    function slideList() {
        //리스트 초기화
        if ($('.slider .list').parent().hasClass('swiper-slide')) {
            $('.slider .swiper-slide-duplicate').remove();
            $('.slider .list').unwrap('swiper-slide');
        }

        //보이는 슬라이드 개수 설정
        $(".slider").each(function(index) {
            if (window.innerWidth > 768) { //PC 버전
                view = 6;
            } else { //mobile 버전
                view = 2;
            }

            //리스트 그룹 생성 (swiper-slide element 추가)
            var num = 0;
            $(this).addClass("slider-" + index);
            $(".slider-" + index).find('.list').each(function(i) {
                $(this).addClass("list" + (Math.floor((i + view) / view)));
                num = Math.floor((i + view) / view)
            }).promise().done(function() {
                for (var i = 1; i < num + 1; i++) {
                    $(".slider-" + index).find('.list' + i + '').wrapAll('<div class="swiper-slide"></div>');
                    $(".slider-" + index).find('.list' + i + '').removeClass('list' + i + '')
                }
            });
        }).promise().done(function() {
            sliderStart()
        });
    }

    function sliderStart() {
        $(".slider").each(function(index) {
            //슬라이드 초기화
            if (swiperArr[index] != undefined) {
                swiperArr[index].destroy();
                swiperArr[index] == undefined;
            }

            //슬라이드 실행
            swiperArr[index] = new Swiper('.slider-' + index + ' .inner', {
                slidesPerView: 1,
                initialSlide: Math.floor(realInx[index] / view),
                resistanceRatio: 0,
                loop: true,
                navigation: {
                    nextEl: $('.slider-' + index).find('.swiper-next')[0],
                    prevEl: $('.slider-' + index).find('.swiper-prev')[0],
                },
                on: {
                    slideChange: function() {
                        realInx[index] = this.realIndex * view
                    }
                },
            });

            //슬라이드 배열 값 추가
            if (swiperArr[index] == undefined) {
                swiperArr[index] = swiper;
            }
        });
    }
}

같은 페이지에 해당 슬라이드가 두 개 이상 들어갈 경우를 대비하여 each 문도 추가했다.
각각의 슬라이드에 필요한 변수는 배열로 선언하여 구현했다.

Licensed under CC BY-NC-SA 4.0
마지막 수정: Mar 09, 2023 00:00 UTC
comments powered by Disqus
Hugo로 만듦
JimmyStack 테마 사용 중