vue3-carousel
vue3-carousel copied to clipboard
Breakpoint Navigation broken
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++
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
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 }); }
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.
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);
},