Para implementar funcionalidades avançadas de rolagem em aplicações Vue, como atualização ao puxar para baixo e carregamento ao rolar até o final, uma solução eficaz é utilizar a biblioteca better-scroll. Ela oferece alto desempenho e controle fino sobre eventos de rolagem em dispositivos móveis e desktops.
Instalação do better-scroll
A primeira etapa é instalar a biblioteca via gerenciador de pacotes. Utilizendo npm ou cnpm, execute:
npm install better-scroll --save
Criação de um componente reutilizável
Como o better-scroll será usado em múltiplos locais da aplicação, é recomendado encapsulá-lo em um componente Vue personalizado. Isso facilita a reutilização e centraliza a lógica de inicialização e eventos.
Estrutura do componente Scroll
O funcionamento do better-scroll depende de uma estrutura HTML específica: um contêiner externo (wrapper) com altura fixa e um conteúdo interno (content) que pode exceder esse limite, permitindo a rolagem.
Abaixo está a implementação de um componente Scroll.vue que envolve o better-scroll com suporte a propriedades configuráveis:
<template>
<div class="scroll-wrapper" ref="scrollContainer">
<div class="scroll-content">
<slot></slot>
</div>
</div>
</template>
<script>
import BScroll from 'better-scroll';
export default {
name: 'Scroll',
props: {
// Define o nível de detecção de posição durante a rolagem
// 1: desativado, 2: ativo (exceto movimento inercial), 3: ativo para todos
listenScroll: {
type: Number,
default: 0
},
// Habilita a funcionalidade de carregamento ao rolar até o fim
enablePullUp: {
type: Boolean,
default: false
},
// Habilita a rolagem com mouse (útil em web)
useMouseWheel: {
type: Boolean,
default: true
}
},
data() {
return {
scrollInstance: null
};
},
mounted() {
this.$nextTick(() => {
this.initScroll();
});
},
methods: {
initScroll() {
const config = {
probeType: this.listenScroll,
pullUpLoad: this.enablePullUp,
mouseWheel: this.useMouseWheel,
click: true,
disableMouse: !this.useMouseWheel,
disableTouch: false
};
this.scrollInstance = new BScroll(this.$refs.scrollContainer, config);
// Emite evento com a posição atual ao rolar
if (this.listenScroll > 1) {
this.scrollInstance.on('scroll', (position) => {
this.$emit('scroll', position);
});
}
// Detecta quando o usuário rola até o final
if (this.enablePullUp) {
this.scrollInstance.on('pullingUp', () => {
this.$emit('load-more');
// Após processar, sinaliza que o carregamento terminou
setTimeout(() => {
this.scrollInstance.finishPullUp();
this.scrollInstance.refresh();
}, 500);
});
}
},
// Método para rolar programaticamente
scrollTo(x, y, time = 400) {
this.scrollInstance && this.scrollInstance.scrollTo(x, y, time);
},
// Atualiza o tamanho do scroll (útil após mudanças no DOM)
refresh() {
this.scrollInstance && this.scrollInstance.refresh();
},
// Força uma nova observação do conteúdo
rebuild() {
this.$nextTick(() => {
this.refresh();
});
}
},
watch: {
// Recarrega o scroll se as opções mudarem dinamicamente
enablePullUp() {
this.rebuild();
}
}
};
</script>
<style scoped>
.scroll-wrapper {
overflow: hidden;
position: relative;
}
.scroll-content {
position: relative;
z-index: 1;
}
</style>
Uso no componente pai
No componente onde deseja usar a rolagem, importe e registre o Scroll, definindo as dimensões do contêiner conforme necessário. Por exemplo:
<template>
<div style="height: 100vh; overflow: hidden;">
<Scroll
:listenScroll="3"
:enablePullUp="true"
@scroll="onScroll"
@load-more="onLoadMore"
ref="scrollComponent"
>
<div v-for="item in list" :key="item.id">{{ item.name }}</div>
</Scroll>
</div>
</template>
É essencial definir height: 100vh (ou outro valor fixo) no contêiner pai, pois o better-scroll precisa de uma altura definida para calcular a rolagem corretamente.
Dicas importantes
- Chame
this.$refs.scrollComponent.refresh()sempre que o conteúdo interno for alterado dinamicamente. - Evite colocar estilos de altura diretamente no componente
Scroll; deixe isso sob responsabilidade do componente pai para maior flexibilidade. - Utilize
$nextTickao inicializar o scroll para garantir que o DOM esteja montado.