如何在VueJS组件中监听窗口滚动事件?

时间:2017-08-22 15:50:13

标签: javascript vue.js vuejs2

我想听听Vue组件中的窗口滚动事件。这是我到目前为止所尝试的:

SELECT CONVERT(datetime,funded,103) AS funded
FROM table

在我的组件方法中定义了<my-component v-on:scroll="scrollFunction"> ... </my-component> ,但它似乎无法正常工作。

任何人都知道如何做到这一点?

谢谢!

10 个答案:

答案 0 :(得分:68)

其实我找到了解决方案。我在创建组件时在scrollFunction(event)事件上添加了一个事件监听器。此外,请确保在销毁组件时删除事件侦听器。

scroll

希望这有帮助!

答案 1 :(得分:5)

我知道这是一个老问题,但是我找到了Vue.js 2.0+ Custom Directives更好的解决方案:我也需要绑定滚动事件,然后我实现了它。

首先,使用@vue/cli,将自定义指令添加到src/main.js(在Vue.js实例之前)或在任何启动它的位置:

Vue.directive('scroll', {
  inserted: function(el, binding) {
    let f = function(evt) {
      if (binding.value(evt, el)) {
        window.removeEventListener('scroll', f);
      }
    }
    window.addEventListener('scroll', f);
  }
});

然后,将自定义v-scroll指令添加到要绑定的元素和/或组件。当然,您必须插入一个专用方法:我在示例中使用了handleScroll

<my-component v-scroll="handleScroll"></my-component>

最后,将您的方法添加到组件中。

methods: {
  handleScroll: function() {
    // your logic here
  }
}

这里不再需要关心Vue.js生命周期,因为自定义指令本身就可以。

答案 2 :(得分:4)

您的要求是在组件上,但是最后增加了主体,而不是在组件上。当然,您也可以在特定元素上执行此操作,但是,嘿...这就是直接与Vue自定义组件一起使用的功能。

 <MyCustomComponent nativeOnScroll={this.handleScroll}>

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

并为handleScroll定义一个方法。简单!

答案 3 :(得分:3)

这样的事情怎么办?顺便说一下,这是 Vue 3

setup() {
    function doOnScroll(event) {
      window.removeEventListener("scroll", doOnScroll);
      console.log("stop listening");
      // your code here ....
      setTimeout(() => {
        window.addEventListener("scroll", doOnScroll, { passive: true });
        console.log("start listening");
      }, 500);
    }

    window.addEventListener("scroll", doOnScroll, { passive: true });
  }

这里的想法是只侦听滚动事件一次,执行您的脚本,然后在 setTimeout 函数中延迟再次重新附加滚动侦听器。如果在此延迟之后页面仍在滚动,则将再次处理滚动事件。 基本上滚动事件每 500 毫秒只监听一次(在这个例子中)。

我使用它只是为了在滚动过程中添加一个 css 类以移开按钮。

答案 4 :(得分:1)

根据我的经验,滚动到事件流中使用事件监听器会产生大量噪音,如果您正在执行庞大的handleScroll函数,则会导致性能问题。

我经常在评分最高的答案中使用此处显示的技术,但我会在其上添加去抖动功能,通常大约100ms会产生良好的性能与用户体验比率。

以下是使用评分最高的答案并添加了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的值分别更改为01000,这样您就可以了解调用handleScroll的方式/时间的差异。

奖励:您还可以使用vue-scroll之类的库,以更加简洁和可重用的方式来完成此任务。如果您尚未了解Vue中的自定义指令,那么这是一个很好的用例。检出https://github.com/wangpin34/vue-scroll

这也是Sarah Drasner在Vue文档中的出色教程:https://vuejs.org/v2/cookbook/creating-custom-scroll-directives.html

答案 5 :(得分:1)

我认为最好的方法是添加“ .passive”

v-on:scroll.passive='handleScroll'

答案 6 :(得分:1)

这不会刷新您的组件,我通过使用Vux解决了问题 为vuex“页面”创建模块

export const state = {
    currentScrollY: 0,
};

export const getters = {
    currentScrollY: s => s.currentScrollY
};

export const actions = {
    setCurrentScrollY ({ commit }, y) {
        commit('setCurrentScrollY', {y});
    },
};

export const mutations = {
    setCurrentScrollY (s, {y}) {
       s.currentScrollY = y;
    },
};

export default {
    state,
    getters,
    actions,
    mutations,
};

在App.vue中:

created() {
    window.addEventListener("scroll", this.handleScroll);
  },
  destroyed() {
    window.removeEventListener("scroll", this.handleScroll);
  },
  methods: {
    handleScroll () {
      this.$store.dispatch("page/setCurrentScrollY", window.scrollY);
      
    }
  },

在您的组件中:

  computed: {
    currentScrollY() {
      return this.$store.getters["page/currentScrollY"];
    }
  },

  watch: {
    currentScrollY(val) {
      if (val > 100) {
        this.isVisibleStickyMenu = true;
      } else {
        this.isVisibleStickyMenu = false;
      }
    }
  },

效果很好。

答案 7 :(得分:0)

我已经多次需要此功能,因此我将其提取到mixin中。可以这样使用:

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

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

这会在Vue实例上创建一个反应性position属性(可以命名为任意名称)。该属性包含窗口滚动位置作为[x,y]数组。

随时可以和this CodeSandbox demo一起玩。

这是mixin的代码。它经过了彻底的评论,因此不难理解其工作原理:

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

答案 8 :(得分:-1)

document.addEventListener('scroll', function (event) {
    if ((<HTMLInputElement>event.target).id === 'latest-div') { // or any other filtering condition
  
    }
}, true /*Capture event*/);

您可以使用它来捕获事件,这里的“latest-div”是 ID 名称,因此您可以根据 ID 捕获此处的所有滚动操作,您也可以在此处执行操作。

答案 9 :(得分:-1)

结合 this.$vuetify.breakpoint.name 和按需加载,滚动事件是一个非常有用的功能。

使用触发器。例如,一个标签:

<v-tabs
  v-bind:grow="!isFullScreen()"
  v-bind:vertical="isFullScreen()"
>

一些类属性:

private isUserScrolling: boolean = false;
private isLoaded: boolean = false;
private startScroll: number = 3;

对触发器做出反应的函数(必要时进行调整):

private isFullScreen(): boolean {
    switch (this.$vuetify.breakpoint.name) {
      case "xs":
        this.startScroll = 500;
        return false;
      case "sm":
        this.startScroll = 300;
        return false;
      case "md":
        this.startScroll = 100;
        return true;
      case "lg":
        this.startScroll = 50;
        return true;
      case "xl":
        this.startScroll = 3;
        return true;
    }
}

添加您的活动:

created() {
   window.addEventListener("scroll", this.handleScroll);
}

对您的活动做出反应:

private handleScroll(event: any): void {
   this.isUserScrolling = window.scrollY > this.startScroll;
   
   if (this.isUserScrolling && !this.isLoaded) {
     // load your stuff
     ...
     this.isLoaded = true;
   }
}