在Vue中使用requestAnimationFrame观察滚动位置

时间:2019-09-02 10:54:21

标签: javascript vue.js

当前,我正在尝试在我的代码中实现requestAnimationFrame()。我的目标是观察窗口的当前scrollPosition并不断更新变量。

我的Vue单个文件组件的代码:

<script>
   data() {
      return {
         scrollPosition: 0
      }
   },
   methods: {
      updateScrollPosition() {
         this.scrollPosition = window.scrollY
         window.requestAnimationFrame(this.updateScrollPosition())
      }
   },
   created() {
      this.updateScrollPosition()
   }
</script>

https://jsbin.com/gizamohuxu/edit?html,js,console,output

我希望scrollPosition会根据窗口的实际滚动位置而不断变化。但是实际上我得到InternalError: "too much recursion"。因此,基本上我觉得我不太了解此requestAnimationFrame()函数-需要帮助。谢谢!

2 个答案:

答案 0 :(得分:1)

您直接在语句中调用updateScrollPosition()并将结果传递给requestAnimationFrame

window.requestAnimationFrame(this.updateScrollPosition());

您需要将函数直接传递给requestAnimationFrame,例如:

// pass function to requestAnimationFrame
window.requestAnimationFrame(this.updateScrollPosition);

然后它将按预期工作。

如果您想在用户滚动时得到通知,则应该使用scroll事件,但是您可以通过addEventListener订阅该事件:

new Vue({
  data() {
    return {
      scrollPosition: 0
    };
  },
  methods: {
    updateScrollPosition() {
      this.scrollPosition = window.scrollY;
    }
  },
  created() {
    window.addEventListener("scroll", this.updateScrollPosition);
  },
  beforeDestroy() {
    // remove listener again
    window.removeEventListener("scroll", this.updateScrollPosition);
  }
});

也请记住,一旦不再需要使用removeEventListener清理注册的侦听器。

答案 1 :(得分:0)

我相信使用requestAnimationFrame实现此功能实际上会降低浏览器的性能。

重要

以上说法不正确。您可以使用requestAnimationFrame来限制滚动事件,使其更有效,如MDN所示。

您实质上创建了无限循环,这就是超出调用堆栈的原因。我会使用scroll上的addEventListener来监听window事件。

示例

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!',
    scrollPosition: 0,
    ticking: false
  },
  methods: {
     updateScrollPosition() {
       this.scrollPosition = window.scrollY;   
       
       if (!this.ticking) {
          window.requestAnimationFrame(function() {
          
          // do something

          this.ticking = false;
        });

          this.ticking = true;
      }
     }
  },
  created() {    
    window.addEventListener('scroll', this.updateScrollPosition);
  }
})
#app {
  position: fixed;
  background: white;
  top: 0;
  left: 0;
  right: 0;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<div id="app">
  {{ message }}
  {{ scrollPosition }}
</div>
  <div>scroll</div>
  <div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div><div>scroll</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
  
</body>
</html>