vue3-carousel icon indicating copy to clipboard operation
vue3-carousel copied to clipboard

Breakpoint Navigation broken

Open kode8 opened this issue 1 year ago • 5 comments

Describe the bug Go to https://ismail9k.github.io/vue3-carousel/examples.html Go to breakpoints example Click the right arrow to the very end, and click a few more ie. 10 times...then click the left arrow. You will notice you have to hit it multiple times before it shifts. Disabled buttons are not disabled and causing a count++

kode8 avatar Sep 27 '23 11:09 kode8

I second this. It works if there is only one item-to-show but if there are multiple items-to-show AND wrap-around = false this bug occurs (like the official breakpoints example).

In the HTML Code you can see that there must be a mismatch between the items count and the items-to-show because the count acts like items-to-show is set to 1. <div class="carousel__liveregion carousel__sr-only" aria-live="polite" aria-atomic="true">Item 5 of 10</div>

Expected behavior: next and prev know how many slides are set to visible and are working correctly

biancajs avatar Oct 24 '23 13:10 biancajs

Hello, I had the same issue and as I find this carousel to be the best available I decided to fix it myself and the patch is not so complicated. The function updateSlidesData that is responsible for handling maxSlideIndex property fires only on a change of the carousel props or the slides collection but the breakpoints config applies later and the given function does not operate on the current configuration changed by the current view (config.itemsToShow is likely being changed on the responsive view). So I have wrapped the body of the function with a watch on the relevant property so its implementation is like this and it finally works as desired:

function updateSlidesData() { watch(() => config.itemsToShow, () => { if (slidesCount.value <= 0) return; middleSlideIndex.value = Math.ceil((slidesCount.value - 1) / 2); maxSlideIndex.value = getMaxSlideIndex({ config, slidesCount: slidesCount.value }); minSlideIndex.value = getMinSlideIndex({ config, slidesCount: slidesCount.value }); if (!config.wrapAround) { currentSlideIndex.value = getNumberInRange({ val: currentSlideIndex.value, max: maxSlideIndex.value, min: minSlideIndex.value, }); } }, { immediate: true }); }

jsikorjak avatar Dec 08 '23 10:12 jsikorjak

Hello, I had the same issue and as I find this carousel to be the best available I decided to fix it myself and the patch is not so complicated. The function updateSlidesData that is responsible for handling maxSlideIndex property fires only on a change of the carousel props or the slides collection but the breakpoints config applies later and the given function does not operate on the current configuration changed by the current view (config.itemsToShow is likely being changed on the responsive view). So I have wrapped the body of the function with a watch on the relevant property so its implementation is like this and it finally works as desired:

function updateSlidesData() { watch(() => config.itemsToShow, () => { if (slidesCount.value <= 0) return; middleSlideIndex.value = Math.ceil((slidesCount.value - 1) / 2); maxSlideIndex.value = getMaxSlideIndex({ config, slidesCount: slidesCount.value }); minSlideIndex.value = getMinSlideIndex({ config, slidesCount: slidesCount.value }); if (!config.wrapAround) { currentSlideIndex.value = getNumberInRange({ val: currentSlideIndex.value, max: maxSlideIndex.value, min: minSlideIndex.value, }); } }, { immediate: true }); }

I'm trying to use this in a blade template,so it would be good to have this patch written into the component....Can you fork this and do it? Or can you show the full code.

ottz0 avatar Dec 15 '23 00:12 ottz0

My solution - updateSlidesData on mount and window resize

<carousel 
        :items-to-show="1"
        :breakpoints="breakpoints"
        snapAlign="start" 
        ref="slider"
    >
...
const debounce = function (fn, delay) {
  let timerId;
  return function (...args) {
    if (timerId) {
      clearTimeout(timerId);
    }
    timerId = setTimeout(() => {
      fn(...args);
      timerId = null;
    }, delay);
  };
}

//.......

methods: {
    onResize() {
      if (!this.$refs.slider) {
        return
      }
      this.$refs.slider.updateSlidesData();
    }

  },
  mounted() {
    window.addEventListener('resize', debounce(this.onResize, 200), {
      passive: true,
    })
    setTimeout(() => {
      this.onResize();
    }, 500)
  },
  beforeUnmount() {
    window.removeEventListener("resize", this.onResize);
  },

AndreyMyagkov avatar Feb 05 '24 15:02 AndreyMyagkov