Reputation: 700
I have a very simple app, that has 2 components: the App.vue
and another component, Home.vue
where I hold the rest of the structure of the app: a sticky header and some sections with anchors to scroll to.
I want to apply a class to the sticky header to minimize the logo while the page is scrolled. So I thought I'd watch for any changes in window.scrollY
. So if scrollY
is greater than 0, apply some class that minimizes the logo.
I tried to listen to scroll events in my component, but that didn't go very far. In this discussion here, a very good solution is provided, but I don't know where to place the scroll event. https://github.com/vuejs/Discussion/issues/324
So, I thought the most fitting solution would be to create a data property, assign it the window.scrollY
figure and then watch for changes in its value. Unfortunately, the watcher is never triggered. So now I'm stuck. The code is:
data () {
return {
...
windowTop: window.top.scrollY
}
}
...
watch: {
windowTop: {
immediate: true,
handler (newVal, oldVal) {
console.log(newVal, oldVal);
},
}
}
Any ideas of what I might be doing wrong?
Upvotes: 14
Views: 38659
Reputation: 138696
window
properties can't be used reactively like that. Instead, you'd have to listen to the window
's scroll
event and respond accordingly:
mounted() {
window.addEventListener("scroll", this.onScroll)
},
beforeDestroy() {
window.removeEventListener("scroll", this.onScroll)
},
methods: {
onScroll(e) {
this.windowTop = window.top.scrollY /* or: e.target.documentElement.scrollTop */
}
}
Upvotes: 38
Reputation: 123
I was trying to do something where I just have to call a variable or function to get the window scroll position in any component. So in order to achieve that I end up using mixins. Here is my code. I am using nuxt.
Inside plugin create a file eg. scroll-position.js
import Vue from 'vue'
Vue.mixin({
data() {
return {
scrollPosition: window.scrollY
}
},
methods: {
get_scroll_position() {
window.addEventListener('scroll', () => {
this.scrollPosition = window.scrollY;
});
return this.scrollPosition
}
}
})
In nuxt.config.js
plugins:['@/plugins/scroll-position.js']
Now you can use get_scroll_position() in any component you want Something like this
:class="{'header_sticky':get_scroll_position()>=80}"
Upvotes: 0
Reputation: 2240
For me none of the above worked.
I had to pass true
as 3rd parameter in add/remove scroll listener:
mounted() {
window.addEventListener("scroll", this.onScroll, true)
},
beforeDestroy() {
window.removeEventListener("scroll", this.onScroll, true)
},
methods: {
onScroll(e) {
this.windowTop = e.target.scrollTop;
}
}
3rd parameter: You should be able to attach a document-level listener with a third parameter of true to capture the scroll events on all elements. Here's what that looks like:
document.addEventListener('scroll', function(e){ }, true);
The true at the end is the important part, it tells the browser to capture the event on dispatch, even if that event does not normally bubble, like change, focus, and scroll.
Upvotes: 13
Reputation: 9583
2020 Updated:
Use @scroll.passive
to watch scroll of any element in component:
Example:
Template
<div class="room_message-stream" @scroll.passive="handleScroll">
<ul class="room_message-stream__list">
<li class="room_message-stream__list-item">...</li>
</ul>
</div>
Methods:
handleScroll (e) {
var scrollPos = e.target.scrollTop
}
Upvotes: 6
Reputation: 15616
You can use the mounted()
method to add your event listener to the window object like this:
var p = new Vue({
el: "#app",
data(){
return {
windowTop: 0
};
},
mounted()
{
var that = this;
window.addEventListener("scroll", function(){
that.windowTop = window.scrollY;
});
},
template: "<div style='height: 250vh'><div style='position: fixed; right: 0; top: 0'>{{windowTop}}</div></div>"
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
Upvotes: 0