[트러블슈팅] swiper loop 모드에서 click event 2개 넣기/ loop 모드에서 duplicate 슬라이드가 깜빡이는 문제

물음표살인마·2024년 10월 4일

트러블슈팅

목록 보기
1/2
post-thumbnail

[개요]

  • vue 2.7 setup script, typescript 사용

프로젝트를 진행하는 중 swiper를 사용해서 슬라이드를 구현하는 부분이 있었다.
이 부분은 loop 기능을 추가해서 무한으로 옆으로 넘길 수 있는 형태이다.

[문제]

1. 클릭 이벤트가 2개 여야함.

  • 맨 처음 화면이 렌더링될때 보이는 왼쪽 2개의 이미지는 가상요소이다. (loop 기능 때문)
  • 슬라이드에 클릭이벤트를 적용한 것이 가상요소에는 적용이 되지 않는다.
  • swiper option의 click 이벤트에 정의를 하면 되지만 기본적으로 1개의 클릭이벤트가 적용된다.
  • 여기서는 상품 이미지를 클릭하는 것과 아래의 동그라미 이미지를 클릭하는 것의 동작이 다르다.

2. 가상요소가 깜빡이는 문제가 있음

  • 스와이퍼에 hover 를 하면 양옆 페이지네이션 버튼의 background를 넣어주고 hover 하지 않을 시 background를 없애주는 기능이 있다.
  • hover 를 할 때마다 템플릿이 다시 렌더링되는 것으로 추정. 스와이퍼가 다시 그려지면서 가상 요소 부분이 흰색이 되었다가 이미지가 나타나는 것으로 추정된다.

[해결]

1. swiper slide에 클릭 이벤트 두개 넣기

  • template 코드
<div ref="swiperRef">
  <swiper
      v-if="productList?.length"
      :options="swiperOption">
          <swiper-slide
              v-for="(product, idx) in productList"
              :key="idx">
                  <custom-component/>
          </swiper-slide>
  </swiper>
</div>
  • swiperOption
const swiperOption: SwiperOptions = {
	simulateTouch: true,
	navigation: {
		nextEl: '.home-top-next-btn',
		prevEl: '.home-top-prev-btn',
	},
	autoplay: { disableOnInteraction: false, delay: 2000 },
	loop: true,
	centeredSlides: true,
	slidesPerView: 'auto',
	spaceBetween: 8,
	touchStartPreventDefault: false,
	speed: 600,
	on: {
		init(this) {
			swiperRef.value = this as SwiperComponent;
			setObserveRef(this);
		},

		click(this, event) {
			const target = event?.target;
			if (!(target instanceof HTMLElement)) return;
			if (!swiperRef.value || !swiperRef.value.clickedSlide) return;
          
			const clickedSlide = swiperRef.value.clickedSlide;
			const clickedSlideIdx = clickedSlide.dataset.swiperSlideIndex;
          
			const isClickStore = target.closest('.new-trend-insights-store');
			const isClickGoods = target.closest('.new-trend-insights-goods');
          
			const goods = productList.value?.[Number(clickedSlideIdx)];
          
			if (!clickedSlideIdx || !goods) return;
			

			if (isClickStore) {
				//store 이미지를 클릭했을 때 실행되는 액션
			} else if (isClickGoods) {
				// 상품 이미지를 클릭했을 때 실행되는 액션
			}
		},
		slideChange(this) {
			swiperRef.value = this as SwiperComponent;
		},
	},

	threshold: 5,
};

swiperOption 에서 click 이벤트를 정의한다.
상품 이미지 카드에 class로 .new-trend-insights-goods 를 주고
스토어 이미지 카드에 class로 .new-trend-insights-store 를 준다.
(포인트는 다른 클래스명을 준다는 뜻)
클릭 이벤트가 발생했을 때 target.closet 으로 클릭된 요소를 찾아서
클릭이 발생한 요소에 해당하는 액션을 정의한다.
이렇게 하면 각각에 이벤트를 줄 수 있다!

2. 가상요소가 깜빡이지 않게하기(재렌더링 안되게 하기)

swiper에 호버를 했을 시 양옆 페이지네이션 버튼의 bg를 넣어주고 호버하지 않았을 시에는 bg를 빼는 코드가 있었다. 

const isHovered = ref(false);
<div
	ref="swiperRef"
	@mouseenter="onMouseEnter"
	@mouseleave="onMouseLeave">
  <swiper 관련 코드 .../>
  <button
	 class="home-top-prev-btn absolute left-[40px] top-[50%] z-[1] translate-y-[-50%] p-[12px]"
	:class="{ 'bg-black-020': isHovered }">
						...
  </button>
  <button
		class="home-top-next-btn absolute right-[40px] top-[50%] z-[1] translate-y-[-50%] p-[12px]"
		:class="{ 'bg-black-020': isHovered }">
					...
  </button>
</div>
            

기존에는 mouseEnter, mouseLeave 이벤트가 발생할 때 마다 isHovered값을 변경해주고 그 변경된 값을 가지고 tailwind class를 동적으로 넣어주고 있었다. 이 state가 바뀔 때 마다 button만 리렌더링되는 게 아니라 swiper 도 리렌더링되었다.

그래서 해결은 state를 사용하지 않고 tailwind의 group을 사용해서 css 만 변경시켜주는 것으로 수정했다. tailwind를 사용하지 않는다면 element를 직접 선택해서 스타일을 바꿔주는 것과 동일하다.

<div
	ref="swiperRef"
    class="group"
	@mouseenter="onMouseEnter"
	@mouseleave="onMouseLeave">
  <swiper 관련 코드 .../>
  <button
	 class="home-top-prev-btn group-hover:bg-black-020 absolute left-[40px] top-[50%] z-[1] translate-y-[-50%] p-[12px]"
	:class="{ 'bg-black-020': isHovered }">
						...
  </button>
  <button
		class="home-top-next-btn group-hover:bg-black-020 absolute right-[40px] top-[50%] z-[1] translate-y-[-50%] p-[12px]"
		:class="{ 'bg-black-020': isHovered }">
					...
  </button>
</div>

group 클래스를 설정한 태그에 hover, focus, active 이벤트가 발생했을 때 자식요소의 class를 바꿀 수 있다.
위의 코드에서 보면 div에 group클래스가 있고
자식인 button에 group-hover:bg-black-020 클래스가 있다.
div에 hover 이벤트가 발생하면 자식인 button에 bg클래스를 준다는 뜻!

[결론]

라이브러리를 사용한다고 해서 꼭 라이브러리에 있는 기능이 아니더라도 기존 지식을 활용해서 창의적으로 문제 해결 방법을 찾아야 한다.

profile
웹 프론트엔드 개발자

0개의 댓글