0

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.

Template

<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>

Javascript

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])
        }
    }
}

Sass

.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

Console Output when scrolling down

[100, 0]

This is how it looks

enter image description here

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer :) I tryed it and it works but only between or below the icons. If I hover over an Icon and scroll, it does nothing but still sending my console.log
1

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).

1 Comment

Thanks for the answer. I just changed event.target to event.currentTarget and now everything works fine. But thanks for the new approach with the camel thing. Another term that I can now learn. Maybe in future projects, I going with you approach 😊👍

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.