如何利用getBoundingClientRect判断与固定INFO区块重叠超80%的轮播区块并输出其标识
解决轮播区块与固定INFO区块的重叠检测问题
我看到你现在的问题是重叠检测逻辑搞错了对象(检测了slide之间而非slide和INFO区块),而且无法识别哪个slide满足重叠条件。下面一步步帮你修复这个问题:
关键问题分析
- 你当前的
checkOverlap函数在检测不同slide之间的重叠,而不是每个slide和.infoblock的重叠 - 只在初始化时执行了一次检测,轮播移动后不会重新检测
- 没有关联每个slide的标识(ONE/TWO/THREE)来输出对应内容
解决方案步骤
1. 给每个slide添加唯一标识
首先在HTML的slide元素上添加data-slide-id属性,方便后续识别是哪个slide:
<div class="slide slide-1" data-slide-id="1"> <div>1</div> </div> <div class="slide slide-2" data-slide-id="2"> <div>2</div> </div> <div class="slide slide-3" data-slide-id="3"> <div>3</div> </div>
2. 修复重叠检测函数
重新编写checkOverlap函数,让它计算单个slide和INFO区块的重叠面积比例,而不是只看垂直方向的偏移。同时获取slide的标识,满足条件时输出对应内容:
const infoBlock = document.querySelector(".infoblock"); function checkSlideOverlapWithInfo() { const infoRect = infoBlock.getBoundingClientRect(); // 计算INFO区块的面积 const infoArea = infoRect.width * infoRect.height; document.querySelectorAll(".slide").forEach(slide => { const slideRect = slide.getBoundingClientRect(); // 计算两个元素的重叠区域坐标 const overlapLeft = Math.max(slideRect.left, infoRect.left); const overlapRight = Math.min(slideRect.right, infoRect.right); const overlapTop = Math.max(slideRect.top, infoRect.top); const overlapBottom = Math.min(slideRect.bottom, infoRect.bottom); // 计算重叠宽度和高度(如果没有重叠则为0) const overlapWidth = Math.max(0, overlapRight - overlapLeft); const overlapHeight = Math.max(0, overlapBottom - overlapTop); const overlapArea = overlapWidth * overlapHeight; // 计算重叠比例(相对于INFO区块的面积,也可以根据需求改为slide的面积) const overlapRatio = overlapArea / infoArea; // 当重叠比例超过80%时输出对应标识 if (overlapRatio >= 0.8) { const slideId = slide.dataset.slideId; console.log(slideId); // 这里会输出1、2、3对应ONE、TWO、THREE slide.classList.add("overlap-80"); } else { slide.classList.remove("overlap-80"); } }); }
3. 确保轮播移动时实时检测
你需要在轮播的关键动作后调用检测函数,比如点击导航按钮后、拖拽结束后,还有初始化时:
- 在
activateAgain函数末尾添加:checkSlideOverlapWithInfo(); - 在
replaceToEnd函数末尾添加:checkSlideOverlapWithInfo(); - 在
moveBasedOnMouse函数末尾添加:setTimeout(checkSlideOverlapWithInfo, 400);(等待过渡动画完成) - 在
setScreenSize函数末尾添加:checkSlideOverlapWithInfo(); - 在
getScreenSize函数末尾添加:checkSlideOverlapWithInfo();
4. 移除原来错误的检测代码
删除你原来的这些错误调用:
checkOverlap(boxes[0], boxes[1]); checkOverlap(boxes[2], boxes[3]); checkOverlap(boxes[4], boxes[5]);
完整修改后的JavaScript代码
var carousel = document.querySelector('.carousel'); var carouselContent = document.querySelector('.carousel-content'); var slides = document.querySelectorAll('.slide'); var arrayOfSlides = Array.prototype.slice.call(slides); var carouselDisplaying; var screenSize; const infoBlock = document.querySelector(".infoblock"); // 添加INFO区块引用 setScreenSize(); var lengthOfSlide; function addClone() { var lastSlide = carouselContent.lastElementChild.cloneNode(true); // 克隆时也要复制data-slide-id属性 lastSlide.dataset.slideId = carouselContent.lastElementChild.dataset.slideId; lastSlide.style.left = (-lengthOfSlide) + "px"; carouselContent.insertBefore(lastSlide, carouselContent.firstChild); } function removeClone() { var firstSlide = carouselContent.firstElementChild; firstSlide.parentNode.removeChild(firstSlide); } function moveSlidesRight() { var slides = document.querySelectorAll('.slide'); var slidesArray = Array.prototype.slice.call(slides); var width = 0; slidesArray.forEach(function (el, i) { el.style.left = width + "px"; width += lengthOfSlide; }); addClone(); } moveSlidesRight(); function moveSlidesLeft() { var slides = document.querySelectorAll('.slide'); var slidesArray = Array.prototype.slice.call(slides); slidesArray = slidesArray.reverse(); var maxWidth = (slidesArray.length - 1) * lengthOfSlide; slidesArray.forEach(function (el, i) { maxWidth -= lengthOfSlide; el.style.left = maxWidth + "px"; }); } window.addEventListener('resize', setScreenSize); function setScreenSize() { if (window.innerWidth >= 500) { carouselDisplaying = 3; } else if (window.innerWidth >= 300) { carouselDisplaying = 2; } else { carouselDisplaying = 1; } getScreenSize(); checkSlideOverlapWithInfo(); // 窗口resize后检测 } function getScreenSize() { var slides = document.querySelectorAll('.slide'); var slidesArray = Array.prototype.slice.call(slides); lengthOfSlide = (carousel.offsetWidth / carouselDisplaying); var initialWidth = -lengthOfSlide; slidesArray.forEach(function (el) { el.style.width = lengthOfSlide + "px"; el.style.left = initialWidth + "px"; initialWidth += lengthOfSlide; }); checkSlideOverlapWithInfo(); // 初始化尺寸后检测 } var rightNav = document.querySelector('.nav-right'); rightNav.addEventListener('click', moveLeft); var moving = true; function moveRight() { if (moving) { moving = false; var lastSlide = carouselContent.lastElementChild; lastSlide.parentNode.removeChild(lastSlide); carouselContent.insertBefore(lastSlide, carouselContent.firstChild); removeClone(); var firstSlide = carouselContent.firstElementChild; firstSlide.addEventListener('transitionend', activateAgain); moveSlidesRight(); } } function activateAgain() { var firstSlide = carouselContent.firstElementChild; moving = true; firstSlide.removeEventListener('transitionend', activateAgain); checkSlideOverlapWithInfo(); // 轮播右移结束后检测 } var leftNav = document.querySelector('.nav-left'); leftNav.addEventListener('click', moveRight); function moveLeft() { if (moving) { moving = false; removeClone(); var firstSlide = carouselContent.firstElementChild; firstSlide.addEventListener('transitionend', replaceToEnd); moveSlidesLeft(); } } function replaceToEnd() { var firstSlide = carouselContent.firstElementChild; firstSlide.parentNode.removeChild(firstSlide); carouselContent.appendChild(firstSlide); firstSlide.style.left = ((arrayOfSlides.length - 1) * lengthOfSlide) + "px"; addClone(); moving = true; firstSlide.removeEventListener('transitionend', replaceToEnd); checkSlideOverlapWithInfo(); // 轮播左移结束后检测 } carouselContent.addEventListener('mousedown', seeMovement); var initialX; var initialPos; function seeMovement(e) { initialX = e.clientX; getInitialPos(); carouselContent.addEventListener('mousemove', slightMove); document.addEventListener('mouseup', moveBasedOnMouse); } function slightMove(e) { if (moving) { var movingX = e.clientX; var difference = initialX - movingX; if (Math.abs(difference) < (lengthOfSlide / 4)) { slightMoveSlides(difference); } } } function getInitialPos() { var slides = document.querySelectorAll('.slide'); var slidesArray = Array.prototype.slice.call(slides); initialPos = []; slidesArray.forEach(function (el) { var left = Math.floor(parseInt(el.style.left.slice(0, -2))); initialPos.push(left); }); } function slightMoveSlides(newX) { var slides = document.querySelectorAll('.slide'); var slidesArray = Array.prototype.slice.call(slides); slidesArray.forEach(function (el, i) { var oldLeft = initialPos[i]; el.style.left = (oldLeft + newX) + "px"; }); } function moveBasedOnMouse(e) { var finalX = e.clientX; if (initialX - finalX > 0) { moveRight(); } else if (initialX - finalX < 0) { moveLeft(); } document.removeEventListener('mouseup', moveBasedOnMouse); carouselContent.removeEventListener('mousemove', slightMove); setTimeout(checkSlideOverlapWithInfo, 400); // 拖拽结束后等待过渡完成再检测 } /* 修复后的重叠检测函数 */ function checkSlideOverlapWithInfo() { const infoRect = infoBlock.getBoundingClientRect(); const infoArea = infoRect.width * infoRect.height; document.querySelectorAll(".slide").forEach(slide => { const slideRect = slide.getBoundingClientRect(); const overlapLeft = Math.max(slideRect.left, infoRect.left); const overlapRight = Math.min(slideRect.right, infoRect.right); const overlapTop = Math.max(slideRect.top, infoRect.top); const overlapBottom = Math.min(slideRect.bottom, infoRect.bottom); const overlapWidth = Math.max(0, overlapRight - overlapLeft); const overlapHeight = Math.max(0, overlapBottom - overlapTop); const overlapArea = overlapWidth * overlapHeight; const overlapRatio = overlapArea / infoArea; if (overlapRatio >= 0.8) { const slideId = slide.dataset.slideId; console.log(slideId); // 输出对应slide的标识 slide.classList.add("overlap-80"); } else { slide.classList.remove("overlap-80"); } }); }
关键点说明
- 标识关联:通过
data-slide-id属性,我们可以轻松获取每个slide的唯一标识,解决了无法识别哪个slide的问题。 - 准确的重叠计算:通过计算两个元素的重叠区域坐标,得到真实的重叠面积比例,比原来只看垂直偏移的逻辑更准确。
- 实时检测:在轮播的所有交互动作(点击导航、拖拽、窗口resize)后都调用检测函数,确保状态更新时能及时检测重叠。
- 克隆slide的处理:克隆slide时复制
data-slide-id属性,避免克隆后的slide丢失标识。
内容的提问来源于stack exchange,提问作者MarkSakhar
相关产品推荐
相关产品推荐

