如何用JavaScript检测DOM中环绕动画元素与固定元素的触碰
嘿,我来帮你搞定这个碰撞检测的需求!你已经搞定了圆形排列的stations和token的环绕动画,接下来要做的就是实时检测两者的碰撞并触发操作,下面是完整的解决方案:
1. 先补全你的圆形排列代码(你之前的代码没写完)
首先把stations排列成圆形的代码补全,确保每个station的位置都正确计算:
$(document).ready(function() { // 把.station元素排列成圆形 const stations = $("#rotator .station").get(); const totalStations = stations.length; const angleIncrement = (Math.PI * 2) / totalStations; const orbitRadius = 150; // 根据你的布局调整这个半径值 const rotatorCenterX = $("#rotator").width() / 2; const rotatorCenterY = $("#rotator").height() / 2; stations.forEach((station, index) => { const currentAngle = angleIncrement * index; // 计算每个station的位置,减去自身宽高的一半让元素居中 const xPos = rotatorCenterX + orbitRadius * Math.cos(currentAngle) - $(station).width() / 2; const yPos = rotatorCenterY + orbitRadius * Math.sin(currentAngle) - $(station).height() / 2; $(station).css({ position: "absolute", left: `${xPos}px`, top: `${yPos}px` }); }); });
2. 核心碰撞检测函数
写一个通用的矩形碰撞检测函数,判断两个元素的边界是否重叠:
function isColliding(el1, el2) { const rect1 = el1.getBoundingClientRect(); const rect2 = el2.getBoundingClientRect(); // 四个方向都不重叠才不算碰撞,取反就是碰撞状态 return !( rect1.top > rect2.bottom || rect1.bottom < rect2.top || rect1.left > rect2.right || rect1.right < rect2.left ); }
3. 实时检测动画中的碰撞
因为#token是CSS动画驱动的,我们要用requestAnimationFrame来同步浏览器渲染帧,确保每帧都检测一次碰撞,这样不会错过任何碰撞瞬间:
$(document).ready(function() { // 先执行上面的圆形排列代码 const token = document.getElementById('token'); const stations = document.querySelectorAll('.station'); let lastHitStation = null; // 记录上一次碰撞的元素,避免重复触发操作 function runCollisionCheck() { stations.forEach(station => { if (isColliding(token, station)) { // 这里写你要执行的特定操作 if (station !== lastHitStation) { console.log(`碰到了station: ${station.dataset.id || station.textContent}`); // 比如给碰撞的station加高亮样式 $(station).addClass('hit'); lastHitStation = station; } } else { // 离开碰撞状态时移除样式(可选) $(station).removeClass('hit'); } }); // 持续检测下一帧 requestAnimationFrame(runCollisionCheck); } // 启动检测 runCollisionCheck(); });
4. 一些优化和注意事项
- 避免重复触发:用
lastHitStation记录上一次碰撞的元素,防止同一station在动画过程中被连续触发N次操作。 - 适配CSS动画:不管你的#token是用
transform还是top/left做动画,getBoundingClientRect()都会正确计算元素的实时位置,所以不用额外处理。 - 性能友好:
requestAnimationFrame只会在浏览器准备渲染的时候执行,比setInterval更高效,不会造成不必要的性能损耗。
举个例子,如果你的#token CSS动画是这样的:
@keyframes orbit { from { transform: rotate(0deg) translateX(150px) rotate(0deg); } to { transform: rotate(360deg) translateX(150px) rotate(-360deg); } } #token { position: absolute; width: 30px; height: 30px; border-radius: 50%; background-color: #ff4444; animation: orbit 8s linear infinite; }
上面的JS检测代码完全能适配这种动画。
内容的提问来源于stack exchange,提问作者shrouk mansour
相关产品推荐
相关产品推荐

