I am using the Sidebar component from BootstrapVue to render a navigation for my application.
As an example, I have 30 menu items in my navigation, so the content within the sidebar scrolls vertically. I would like to bind to that scroll event to dynamiclly add/remove some classes.
I have tried to create a custom scroll directive:
Vue.directive('scroll', {
inserted: function(el, binding) {
console.log('el', el);
let f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
});
...then register that to the component within my vue file:
<b-sidebar
v-scroll="handleScroll"
title="Menu"
shadow="lg"
backdrop
@change="$emit('sidebar-change')"
...
handleScroll() {
console.log('handleScroll');
},
The directive is being picked up properly, but my handleScroll
method is firing when the main body is scrolling, not the sidebar.
In my directive, I am logging to see what element it thinks it's working with:
<div tabindex="-1" class="b-sidebar-outer">...</div>
Since Bootstrap is dynamiclly creating the markup for the overlay, that's the parent element -- looking closer, I believe I need to attach my directive to this:
<div class="b-sidebar-body">...</div>
That is the <div>
that looks to be scrolling. However, since it is generated at runtime, I don't know how to hook into that.
I have also tried using @native.scroll="myMethod"
on the component...no luck there either.
How can I listen for the scroll event within my sidebar component? Thank you for any suggestions!
Your scroll
listener fires on the main window because the directive attached the event listener to window
, and not the element.
To listen to scroll events on the contents of b-sidebar
, the listener should be on an element inside the default slot of b-sidebar
(not the b-sidebar
itself).
Put a wrapper div
inside b-sidebar
's default slot, and style it to enable scrolling:
<template>
<b-sidebar>
<div class="wrapper">
<!-- your actual contents here -->
</div>
</b-sidebar>
</template>
<style>
.wrapper {
overflow: auto;
height: 100%;
}
</style>
Add the custom v-scroll
directive on the wrapper div
:
<div class="wrapper" v-scroll="handleScroll">
Update the custom directive to add the binding value as the event listener on the given element's scroll
event:
Vue.directive('scroll', (el, binding) => {
let f = (evt) => {
if (binding.value(evt, el)) {
el.removeEventListener('scroll', f)
}
}
el.addEventListener('scroll', f)
})