Vue com Better-Scroll: Implementação de Controle de Rolagem com Suporte a Atualização e Carregamento

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 $nextTick ao inicializar o scroll para garantir que o DOM esteja montado.

Tags: vue better-scroll rolagem Pull-to-Refresh carregamento-infinito

Publicado em 8-14 23:53