I want to listen to the window scroll event in my Vue component. Here is what I tried so far:
<my-component v-on:scroll="scrollFunction">
...
</my-component>
With the scrollFunction(event)
being defined in my component methods but it doesn't seem to work.
Anyone has any idea how to do this?
Thanks!
This question is related to
javascript
vue.js
vuejs2
Actually I found a solution. I add an event listener on the scroll
event when the component is created and remove the event listener when the component is destroyed.
export default {
created () {
window.addEventListener('scroll', this.handleScroll);
},
destroyed () {
window.removeEventListener('scroll', this.handleScroll);
},
methods: {
handleScroll (event) {
// Any code to be executed when the window is scrolled
}
}
}
Hope this helps!
this does not refresh your component I solved the problem by using Vux create a module for vuex "page"
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,
};
in App.vue :
created() {
window.addEventListener("scroll", this.handleScroll);
},
destroyed() {
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
handleScroll () {
this.$store.dispatch("page/setCurrentScrollY", window.scrollY);
}
},
in your component :
computed: {
currentScrollY() {
return this.$store.getters["page/currentScrollY"];
}
},
watch: {
currentScrollY(val) {
if (val > 100) {
this.isVisibleStickyMenu = true;
} else {
this.isVisibleStickyMenu = false;
}
}
},
and it works great.
In my experience, using an event listener on scroll can create a lot of noise due to piping into that event stream, which can cause performance issues if you are executing a bulky handleScroll
function.
I often use the technique shown here in the highest rated answer, but I add debounce on top of it, usually about 100ms
yields good performance to UX ratio.
Here is an example using the top-rated answer with Lodash debounce added:
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);
}
}
Try changing the value of 100
to 0
and 1000
so you can see the difference in how/when handleScroll
is called.
BONUS: You can also accomplish this in an even more concise and reuseable manner with a library like vue-scroll
. It is a great use case for you to learn about custom directives in Vue if you haven't seen those yet. Check out https://github.com/wangpin34/vue-scroll.
This is also a great tutorial by Sarah Drasner in the Vue docs: https://vuejs.org/v2/cookbook/creating-custom-scroll-directives.html
I've been in the need for this feature many times, therefore I've extracted it into a mixin. It can be used like this:
import windowScrollPosition from 'path/to/mixin.js'
new Vue({
mixins: [ windowScrollPosition('position') ]
})
This creates a reactive position
property (can be named whatever we like) on the Vue instance. The property contains the window scroll position as an [x,y]
array.
Feel free to play around with this CodeSandbox demo.
Here's the code of the mixin. It's thoroughly commentated, so it should not be too hard to get an idea how it works:
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)
}
}
}
I know this is an old question, but I found a better solution with Vue.js 2.0+ Custom Directives: I needed to bind the scroll event too, then I implemented this.
First of, using @vue/cli
, add the custom directive to src/main.js
(before the Vue.js instance) or wherever you initiate it:
Vue.directive('scroll', {
inserted: function(el, binding) {
let f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
}
window.addEventListener('scroll', f);
}
});
Then, add the custom v-scroll
directive to the element and/or the component you want to bind on. Of course you have to insert a dedicated method: I used handleScroll
in my example.
<my-component v-scroll="handleScroll"></my-component>
Last, add your method to the component.
methods: {
handleScroll: function() {
// your logic here
}
}
You don’t have to care about the Vue.js lifecycle anymore here, because the custom directive itself does.
Here's what works directly with Vue custom components.
<MyCustomComponent nativeOnScroll={this.handleScroll}>
or
<my-component v-on:scroll.native="handleScroll">
and define a method for handleScroll. Simple!
I think the best approach is just add ".passive"
v-on:scroll.passive='handleScroll'
document.addEventListener('scroll', function (event) {
if ((<HTMLInputElement>event.target).id === 'latest-div') { // or any other filtering condition
}
}, true /*Capture event*/);
You can use this to capture an event and and here "latest-div" is the id name so u can capture all scroller action here based on the id you can do the action as well inside here.
Source: Stackoverflow.com