web-dev-qa-db-fra.com

Comment écouter l'événement de défilement de fenêtre dans un composant VueJS?

Je souhaite écouter l'événement de défilement de la fenêtre dans mon composant Vue. Voici ce que j'ai essayé jusqu'à présent:

<my-component v-on:scroll="scrollFunction">
    ...
</my-component>

La scrollFunction(event) étant définie dans mes méthodes de composant, mais cela ne semble pas fonctionner.

Quelqu'un a une idée de comment faire ça?

Merci!

32
jeerbl

En fait, j'ai trouvé une solution. J'ajoute un écouteur d'événement à l'événement scroll lorsque le composant est créé et supprime l'écouteur d'événement lorsque le composant est détruit.

export default {
  methods: {
    handleScroll (event) {
      // Any code to be executed when the window is scrolled
    }
  },
  created () {
    window.addEventListener('scroll', this.handleScroll);
  },
  destroyed () {
    window.removeEventListener('scroll', this.handleScroll);
  }
}

J'espère que cela t'aides!

84
jeerbl

Vos exigences concernaient le composant, mais vous avez fini par ajouter du corps et non du composant. Bien sûr, vous pouvez également le faire sur un élément particulier, mais bon… Voici ce qui fonctionne directement avec Vue composants personnalisés.

 <MyCustomComponent nativeOnScroll={this.handleScroll}>

ou

<my-component v-on:scroll.native="handleScroll">

et définir une méthode pour handleScroll. Facile!

6
kushalvm

D'après mon expérience, l'utilisation d'un écouteur d'événement sur scroll peut créer beaucoup de bruit en raison de la canalisation dans ce flux d'événements, ce qui peut entraîner des problèmes de performances si vous exécutez une fonction volumineuse handleScroll.

J'utilise souvent la technique présentée ici dans la réponse la mieux notée, mais j'y ajoute une option anti-rebond, généralement environ 100ms permet d'obtenir un bon rapport performances/UX.

Voici un exemple utilisant la réponse la mieux notée avec Lodash debounce ajouté:

import debounce from 'lodash/debounce';

export default {
  methods: {
    handleScroll(event) {
      // Any code to be executed when the window is scrolled
      this.isUserScrolling = (window.scrollY > 0);
      console.log('calling handleScroll');
    }
  },

  created() {
    this.handleDebouncedScroll = debounce(this.handleScroll, 100);
    window.addEventListener('scroll', this.handleDebouncedScroll);
  },

  beforeDestroy() {
    // I switched the example from `destroyed` to `beforeDestroy`
    // to exercise your mind a bit. This lifecycle method works too.
    window.removeEventListener('scroll', this.handleDebouncedScroll);
  }
}

Essayez de changer la valeur de 100 en 0 et 1000 pour que vous puissiez voir la différence entre comment/quand handleScroll est appelée.

BONUS: Vous pouvez également accomplir cela de manière encore plus concise et réutilisable avec une bibliothèque comme vue-scroll. C'est un excellent cas d'utilisation pour vous familiariser avec les directives personnalisées dans Vue si vous ne les avez pas encore vues. Départ https://github.com/wangpin34/vue-scroll .

C’est aussi un excellent tutoriel de Sarah Drasner dans la Vue docs: https://vuejs.org/v2/cookbook/creating-custom-scroll-directives.html

5
agm1984

J'ai eu besoin de cette fonctionnalité à plusieurs reprises, donc je l'ai extraite dans un mixin . Il peut être utilisé comme ceci:

import windowScrollPosition from 'path/to/mixin.js'

new Vue({
  mixins: [ windowScrollPosition('position') ]
})

Cela crée une propriété position réactive (pouvant être nommée comme bon nous semble) sur l’instance Vue. La propriété contient la position de défilement de la fenêtre sous la forme d'un tableau [x,y].

N'hésitez pas à jouer avec cette démo de CodeSandbox .

Voici le code du mixin. C'est complètement commenté, donc il ne devrait pas être trop difficile de se faire une idée de son fonctionnement:

function windowScrollPosition(propertyName) {
  return {
    data() {
      return {
        // Initialize scroll position at [0, 0]
        [propertyName]: [0, 0]
      }
    },
    created() {
      // Only execute this code on the client side, server sticks to [0, 0]
      if (!this.$isServer) {
        this._scrollListener = () => {
          // window.pageX/YOffset is equivalent to window.scrollX/Y, but works in IE
          // We round values because high-DPI devies can provide some really nasty subpixel values
          this[propertyName] = [
            Math.round(window.pageXOffset),
            Math.round(window.pageYOffset)
          ]
        }

        // Call listener once to detect initial position
        this._scrollListener()

        // When scrolling, update the position
        window.addEventListener('scroll', this._scrollListener)
      }
    },
    beforeDestroy() {
      // Detach the listener when the component is gone
      window.removeEventListener('scroll', this._scrollListener)
    }
  }
}
2
Loilo