Garantindo a Responsividade do Swiper no Vue.js durante o Redimensionamento da Janela

Ao integrar o Swiper em projetos Vue.js, um problema recorrente é a falha na atualização das dimensões do carrossel quando o usuário redimensiona a janela do navegador. Mesmo utilizando propriedades CSS para manter a proporção, o Swiper frequentemente exige um recálculo interno para ajustar a largura de seus contêineres e slides.

Estratégia 1: Atualização via Reinjeção de Componente

Uma abordagem para garentir que o Swiper sempre reflita o estado atual da janela é forçar a recriação do componente. Podemos utilizar o padrão provide/inject no Vue para disparar uma atualização no componente principal (App.vue) sempre que o evento de resize ocorrer.

No App.vue, configuramos um mecanismo para alternar a visibilidade do roteador:

<template>
  <div id="app-container">
    <router-view v-if="renderContent" />
  </div>
</template>

<script>
export default {
  name: 'App',
  provide() {
    return {
      triggerRefresh: this.refreshComponent
    };
  },
  data() {
    return {
      renderContent: true
    };
  },
  methods: {
    refreshComponent() {
      this.renderContent = false;
      this.$nextTick(() => {
        this.renderContent = true;
      });
    }
  }
};
</script>

No componente do carrossel, injetamos a função e monitoramos o redimensionamento:

<template>
  <div ref="carousel" class="swiper-container">
    <div class="swiper-wrapper">
      <div class="swiper-slide" v-for="(src, idx) in gallery" :key="idx">
        <div class="image-wrapper">
          <img :src="src" class="responsive-img" />
        </div>
      </div>
    </div>
    <div class="swiper-scrollbar"></div>
  </div>
</template>

<script>
import Swiper from 'swiper';
export default {
  inject: ['triggerRefresh'],
  data() {
    return {
      gallery: ["link1.png", "link2.png", "link3.png"],
      instance: null
    };
  },
  mounted() {
    this.initCarousel();
    window.addEventListener('resize', this.triggerRefresh);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.triggerRefresh);
  },
  methods: {
    initCarousel() {
      this.instance = new Swiper(this.$refs.carousel, {
        loop: true,
        width: window.innerWidth * 0.6,
        scrollbar: { el: '.swiper-scrollbar', draggable: true },
        autoplay: { delay: 3000 }
      });
    }
  }
};
</script>

<style>
.image-wrapper {
  height: 0;
  width: 100%;
  padding-bottom: 56.25%; /* Proporção 16:9 */
  position: relative;
}
.responsive-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
</style>

Estratégia 2: Gerenciamento Manual de Instâncias (Keep-Alive)

Quando utilizamos <keep-alive>, o componente não é destruído ao navegar entre rotas, o que invalida o hook mounted em visitas subsequentes. Nesse cenário, o v-if pode não ser a melhor escolha. Uma solução mais performática é destruir e recriar a instância do Swiper manualmente, garantindo que não haja múltiplos objetos ativos simultaneamente, o que causaria aceleração indesejada nas transições.

<script>
import Swiper from 'swiper';

export default {
  data() {
    return {
      activeInstance: null
    };
  },
  methods: {
    setupSwiper() {
      // Destruir instância anterior se existir
      if (this.activeInstance) {
        this.activeInstance.destroy(true, true);
        this.activeInstance = null;
      }

      // Nova inicialização com parâmetros atualizados
      this.activeInstance = new Swiper(this.$refs.carousel, {
        loop: true,
        width: window.innerWidth * 0.58,
        autoplay: { delay: 2500, disableOnInteraction: false }
      });
    },
    handleResize() {
      this.setupSwiper();
    }
  },
  activated() {
    // Hook necessário para componentes dentro de keep-alive
    this.setupSwiper();
    window.addEventListener('resize', this.handleResize);
  },
  deactivated() {
    window.removeEventListener('resize', this.handleResize);
  }
};
</script>

Cosniderações sobre Performance

Ao lidar com o evento resize, é fundamental garantir a limpeza dos listeners. No Vue, isso é feito no beforeDestroy ou, caso esteja usando keep-alive, nos hooks activated e deactivated. O método de destruição manual da instância do Swiper (destroy()) é preferível em aplicações complexas para evitar vazamentos de memória e comportamentos erráticos na interface.

Tags: vuejs swiper javascript responsive-design frontend

Publicado em 8-4 23:20