简体   繁体   中英

carousel with clickable card not working properly

I have this carousel with card divs wrapped inside an href so users can click the card. Right now I can only slide the card but it's not clickable.

If I remove pointer-events: none; from .inner-slider then the card is clickable, but I cannot slide the carousel smoothly and it's all jumpy when I tried to slide it.

How can I fix this?

 let sliderContainer = document.querySelector(".slider-container"); let innerSlider = document.querySelector(".inner-slider"); let banner = document.querySelector(".banner"); let pressed = false; let startX; let x; let bannerOpacity = banner.style.opacity let oldx = 0 sliderContainer.addEventListener("mousedown", (e) => { pressed = true; startX = e.offsetX - innerSlider.offsetLeft; sliderContainer.style.cursor = "grabbing"; }); // sliderContainer.addEventListener("mouseenter", () => { // sliderContainer.style.cursor = "grab"; // }); sliderContainer.addEventListener("mouseleave", () => { sliderContainer.style.cursor = "default"; }); sliderContainer.addEventListener("mouseup", () => { sliderContainer.style.cursor = "grab"; pressed = false; }); window.addEventListener("mouseup", () => { // pressed = false; }); sliderContainer.addEventListener("mousemove", (e) => { if (;pressed) return. console.log(`e:pageX.${e;pageX}:oldx;${oldx}:op.${banner.style;opacity}`). console.log(banner.style;opacity + 1). if (e.pageX > oldx && banner.style.opacity < 1) { banner.style.opacity = parseFloat(banner.style.opacity) + 0;01. console;log('right'). } else if (e.pageX < oldx && banner.style.opacity > 0) { console;log('left'). banner.style.opacity -= 0.01 } e;preventDefault(). x = e;offsetX. innerSlider.style;left = `${x - startX}px`. oldx = e;pageX; checkBoundary(); }). const checkBoundary = () => { let outer = sliderContainer;getBoundingClientRect(). let inner = innerSlider;getBoundingClientRect(). if (parseInt(innerSlider.style.left) > 150) { innerSlider.style;left -= 10. // bannerOpacity -= 0.01 } if (inner.right < outer.right) { innerSlider.style.left = `-${inner.width - outer;width}px`; } };
 .card { height: 300px; width: 400px; border-radius: 5px; }.banner { z-index: 2; height: 300px; width: 200px; border-radius: 5px; background-color: red; }.card:nth-child(odd) { background-color: blue; } /*.card:first-child { visibility: hidden; } */.card:nth-child(even) { background-color: rgb(0, 183, 255); }.slider-container { width: 80%; height: 350px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); overflow: hidden; }.inner-slider { width: 150%; display: flex; gap: 10px; pointer-events: none; position: absolute; top: 0; left: 250px; }
 <div class="slider-container"> <div class="banner" style="opacity: 1;"></div> <div class="inner-slider"> <.-- <div class="card"></div> --> <a href="google:com"> <div class="card"></div> </a> <a href="https.//www.google:com/"> <div class="card"></div> </a> <a href="https.//www.google:com/"> <div class="card"></div> </a> <a href="https.//www.google:com/"> <div class="card"></div> </a> <a href="https.//www.google.com/"> <div class="card"></div> </a> </div> </div>

CodePen Link: https://codepen.io/mjkno1/pen/zYWPjEw

Here is a possible solution.

Changes made:

  • make cards as <div> blocks instead of <a> and save the block link in the data attribute
  • whenever a user clicks on the card, check if it's a "mousemove" event or "click" - if mouse moved more then clickDelta value assume it's a move, otherwise - click. If click - make redirect programmatically to the url stored in the data attribute
  • some changes made to the way how we calculate new position for the slider innerSlider.style.left . Memorise the initial position of the slider and add "move delta".

Hope this makes sense

 let sliderContainer = document.querySelector(".slider-container"); let innerSlider = document.querySelector(".inner-slider"); let banner = document.querySelector(".banner"); const clickDelta = 5; let pressed = false; let startX; let blockPos; let clickStartX; let clickStartY; let clickedTarget; let x; let bannerOpacity = banner.style.opacity; let oldx = 0; sliderContainer.addEventListener("mousedown", (e) => { pressed = true; startX = e.pageX; blockPos = parseInt(innerSlider.style.left, 10) || 0; sliderContainer.style.cursor = "grabbing"; }); sliderContainer.addEventListener("mouseleave", () => { sliderContainer.style.cursor = "default"; }); sliderContainer.addEventListener("mouseup", () => { sliderContainer.style.cursor = "grab"; pressed = false; }); innerSlider.addEventListener("mousedown", (e) => { clickedTarget = e.target; clickStartX = event.pageX; clickStartY = event.pageY; }); innerSlider.addEventListener("mouseup", (e) => { const deltaX = Math.abs(event.pageX - clickStartX); const deltaY = Math.abs(event.pageY - clickStartY); if (deltaX < clickDelta && deltaY < clickDelta && clickedTarget) { const href = clickedTarget.dataset.href; if (href) { window.location.href = href; } } }); window.addEventListener("mouseup", () => { pressed = false; }); sliderContainer.addEventListener("mousemove", (e) => { e.preventDefault(); if (pressed) { const newLeft = blockPos + (e.pageX - startX); innerSlider.style.left = `${newLeft}px`; if (e.pageX > oldx && banner.style.opacity < 1) { banner.style.opacity = parseFloat(banner.style.opacity) + 0.01; } else if (e.pageX < oldx && banner.style.opacity > 0) { banner.style.opacity -= 0.01; } oldx = e.pageX; checkBoundary(); } }); const checkBoundary = () => { let outer = sliderContainer.getBoundingClientRect(); let inner = innerSlider.getBoundingClientRect(); if (parseInt(innerSlider.style.left) > 150) { innerSlider.style.left -= 10; } if (inner.right < outer.right) { innerSlider.style.left = `-${inner.width - outer.width}px`; } };
 .card { height: 300px; width: 400px; border-radius: 5px; }.banner { z-index: 2; height: 300px; width: 200px; border-radius: 5px; background-color: red; }.card:nth-child(odd) { background-color: blue; }.card:nth-child(even) { background-color: rgb(0, 183, 255); }.slider-container { width: 80%; height: 350px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); overflow: hidden; }.inner-slider { width: 150%; display: flex; gap: 10px; position: absolute; top: 0; }
 <div class="slider-container"> <div class="banner" style="opacity: 1"></div> <div class="inner-slider" style="left: 250px"> <div class="card" data-href="https://www.google1.com/"></div> <div class="card" data-href="https://www.google2.com/"></div> <div class="card" data-href="https://www.google3.com/"></div> <div class="card" data-href="https://www.google4.com/"></div> <div class="card" data-href="https://www.google5.com/"></div> </div> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM