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.