[Issue Report] Swiper와 v-for 동시 적용 시, 배열의 첫 번째 요소만 출력되는 문제 (watch, computed 활용 로그 분석)

Jinbro·2023년 3월 18일
0

Issue Report

목록 보기
1/2

배경설명

  • Vuejs는 데이터 변경이 감지되면 자동으로 뷰를 다시 렌더링하여 변경 사항 반영함.
    • v-model, v-for, watch, computed 등
  • 팝업 호출 시, 배열 데이터를 변경하여 전체 목록을 동적으로 렌더링하는 로직 구현

문제인식

  • Swiper 활용한 <li>에 v-for 적용 시, 동적으로 생성된 배열 중 첫번째 요소만 화면에 렌더링되는 현상 발생! 😒

접근방법

  • 데이터 변경과 화면에 렌더링되는 시점 비교를 위해 console log를 남겨보자.
  • Vuejs 인스턴스 내 데이터 변경 감지할 수 있는 방법은 2가지다.

1. watch : 객체의 프로퍼티 감시

data 객체에 선언한 변수를 watch 속성에 등록하여 감시

2. computed : 배열의 요소 감시

data 객체에 선언하지 않은 새로운 변수의 값을 생성하여 반환

샘플소스

  • 배열의 요소를 감시하여 변경 시마다 메세지 출력

html

<div id="app">
  <div class="swiper-container">
    <div class="swiper-wrapper">
      <ul class="ui-swiper">
        <li class="swiper-slide" v-for="(item, idx) in list">
          <p>{{ item }}</p>
        </li>
      </ul>
    </div>
  </div>
</div>

js

new Vue({
  el: '#app',
  data: {
    list: ['Item 1', 'Item 2', 'Item 3']
  },
  computed: {
    itemLength: function() {
      const listLen = this.list.length;
      console.log('[computed] list 변경 감지! : ', listLen);
      return listLen;
    }
  },
  watch: {
    list: function(newVal, oldVal) {
      console.log('[watch] list 변경 감지! : ', oldVal, '에서 ', newVal, '로 변경');
    }
  },
  methods: {
    addItem: function() {
      console.log('[addItem] list 변경 전! : ', this.list);
      this.list.push('Item ' + (this.itemLength + 1));
      console.log('[addItem] list 변경 후! : ', this.list);
    }
  }
});

원인

  • Vuejs는 watch, computed 에 등록된 변수의 변경을 계속 감지하여 DOM에 동적으로 반영하고 있음.
  • 반면, Swiper는 최초 DOM 초기화할 때 생성된 요소만 감지하고, 추후 동적으로 생성된 요소들을 감지하지 못 함.

솔루션

  1. 배열이 변경 완료 시점에, Swiper 객체가 동적으로 변경된 요소 감지할 수 있도록 update() 메소드를 호출
    => 정상 확인 안 됨. 🤣
var swiper = new SwiperVue({
	el: '.swiper-container',
});
swiper.update();
  1. v-for 적용 태그 변경 (임시 편법 🤔)
    => 요소의 개수가 7개 이상일 경우, swiper 제대로 동작 안 함.
  • ASIS : <li>
  • TOBE : <ul>
<div id="app">
  <div class="swiper-container">
    <div class="swiper-wrapper">
      <ul class="ui-swiper" v-for="(item, idx) in list">
        <li class="swiper-slide">
          <p>{{ item }}</p>
        </li>
      </ul>
    </div>
  </div>
</div>

결론

  • 퍼블에서 적용한 custom class "ui-swiper" 제거 -> 정상...😒
<div id="app">
  <div class="swiper-container">
    <div class="swiper-wrapper">
      <ul>
        <li class="swiper-slide" v-for="(item, idx) in list">
          <p>{{ item }}</p>
        </li>
      </ul>
    </div>
  </div>
</div>

참고

profile
자기 개발 기록 저장소

0개의 댓글