Как прослушать событие прокрутки окна в компоненте VueJS?

Я хочу прослушать событие прокрутки окна в моем компоненте Vue. Вот что я пробовал до сих пор:

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

С scrollFunction(event), определяемой в моих методах компонентов, но она не работает.

Кто-нибудь знает, как это сделать?

Спасибо!

Ответы

Ответ 1

На самом деле я нашел решение. Я добавляю прослушиватель событий в событие scroll при создании компонента и удаляю прослушиватель событий, когда компонент уничтожается.

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);
  }
}

Надеюсь, это поможет!

Ответ 2

Ваши требования были к компоненту, но вы закончили с добавлением в теле, а не в компоненте. Конечно, вы можете сделать это и для определенного элемента, но эй... Вот что работает непосредственно с пользовательскими компонентами Vue.

 <MyCustomComponent nativeOnScroll={this.handleScroll}>

или же

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

и определить метод для handleScroll. Просто!

Ответ 3

По моему опыту, использование прослушивателя событий при прокрутке может создать много шума из-за передачи в этот поток событий, что может вызвать проблемы с производительностью, если вы выполняете громоздкую функцию handleScroll.

Я часто использую технику, показанную здесь в ответе с самым высоким рейтингом, но я добавляю debounce поверх него, обычно о 100ms, который дает хорошее соотношение производительности к UX.

Вот пример использования ответа с самым высоким рейтингом и добавлением отклика Lodash:

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);
  }
}

Попробуйте изменить значение 100 на 0 и 1000, чтобы увидеть разницу в том, как/когда вызывается handleScroll.

БОНУС: Вы также можете сделать это еще более кратким и многократно используемым способом с помощью библиотеки, подобной vue-scroll. Это отличный пример использования для вас, чтобы узнать о пользовательских директивах в Vue, если вы их еще не видели. Проверьте https://github.com/wangpin34/vue-scroll.

Это также большое руководство Сары Драснер в документах Vue: https://vuejs.org/v2/cookbook/creating-custom-scroll-directives.html

Ответ 4

Я нуждался в этой функции много раз, поэтому я извлек ее в миксин. Это можно использовать так:

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

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

Это создает свойство реактивной position (может называться как угодно) в экземпляре Vue. Свойство содержит позицию прокрутки окна в виде массива [x,y].

Не стесняйтесь поиграть с этой демонстрацией CodeSandbox.

Здесь код миксина. Это тщательно прокомментировано, поэтому не должно быть слишком сложно понять, как это работает:

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)
    }
  }
}

Ответ 5

Начиная с Vue.js 2.3. 0+ есть модификатор события .passive. Так что он работает как addEventListenner.

<div v-on:scroll.passive="onScroll">...</div>

Модификаторы событий Vue.js

Ответ 6

Я думаю, что лучший подход - просто добавить ".passive"

v-on:scroll.passive='handleScroll'