Reputation: 75
I want to scroll horizontally through icons with my mouse. I tried it with scrollLeft
in Javascript, but the value does not change when scrolling. Only the deltaY
value changes between 100 and -100 when scrolling.
Does anyone have an idea what the issue could be?
When I scroll and the mouse hovers the scrollbar it works but I want this to work on the entire div-container. I also want to do this without dependencies/npm-libraries if possible.
<div class="icons flex_center_h flex_between">
<div class="flex_center_h flex_start instIconContainer"
@wheel="ScrollIcons($event)">
<FilterIcon
v-for="(icon, iconIndex) in rooms[index].description.icons"
:key="icon"
:icon="rooms[index].description.icons[iconIndex].icon"
:customClass="'instIcon'" />
</div>
<FilterIcon :customClass="'navIcon'" :icon="'nav'" />
</div>
import {
FilterIcon
} from '@/components/Elements/'
export default {
components: {
FilterIcon,
},
computed: {
rooms() {
return this.$store.state.rooms
}
},
methods: {
ScrollIcons(event) {
event.preventDefault()
event.target.scrollLeft += event.deltaY
console.log([event.deltaY, event.target.scrollLeft])
}
}
}
.icons
background: $bg
width: 80%
padding: 0.5rem 0.5rem
::-webkit-scrollbar
width: $scrollbarSize
height: 0.3rem
background: $bg-glow
border-radius: $radius_1
::-webkit-scrollbar-thumb
background: $purple
border-radius: $radius_1
.instIconContainer
width: 70%
max-width: calc(40px * 4)
max-height: 80px
overflow-x: auto
.instIcon
width: $IconSize
height: $IconSize
min-width: $IconSize
min-height: $IconSize
path, circle
fill: $purple
[100, 0]
Upvotes: 0
Views: 8854
Reputation: 90287
The problem with your example is event.target
is not the scroller element, but the icon.
Use a ref
to make sure you're targeting the correct element. 1
Another option is to bind to the scrollLeft
HTML property of the element and let Vue handle the DOM updates. You only change the value in the controller.
We use .camel
modifier to bypass the fact that HTML attributes (which is what we use to bind to the property) are case insensitive :scroll-left.camel
2, 3
const { createApp, onMounted, reactive, toRefs } = Vue;
const { min, max } = Math;
createApp({
setup: () => {
const state = reactive({
scroller: null,
scrollLeft: 0,
});
const onWheel = (e) => {
state.scrollLeft = state.scroller
? min(
state.scroller.scrollWidth - state.scroller.offsetWidth,
max(0, e.deltaY + state.scrollLeft)
)
: state.scrollLeft;
};
return { ...toRefs(state), onWheel };
},
}).mount("#app");
#app div span {
min-width: 50%;
display: inline-block;
}
#app div {
display: flex;
overflow-x: auto;
cursor: ew-resize;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.37/vue.global.prod.min.js"></script>
<div id="app">
<div ref="scroller"
@wheel.prevent="onWheel"
:scroll-left.camel="scrollLeft">
<span v-for="n in 5" v-text="n" />
</div>
<pre v-text="{ scrollLeft }" />
</div>
Notes:
1 - Because we're binding to scrollLeft
prop, we don't need the ref
anymore. I left it in because I wanted to limit the controller scrollLeft
value within valid values and needed the ref
to calculate the max.
2 - technically it should be :scroll-left.camel.prop
, since it's an HTML property, but it also works without the .prop
modifier
3 - .scroll-left.camel
also works (shorthand for :scroll-left.camel.prop
).
Upvotes: 1
Reputation: 67
I tried something similar to yours and it wasn't working until I used currentTarget
instead of target
in event.target.scrollLeft += event.deltaY
in your ScrollIcons method. This way when you use your mouse wheel while your cursor is over your icons, you will target the containing div or tag, rather than targeting the icons. In other words whenever your cursor is in the containing div and you mouse wheel, the div should respond regardless of any other elements between the div and mouse cursor.
Upvotes: 1