求助实现鼠标悬停文字打乱复原效果(附jQuery代码)
纯原生JS实现文字悬停打乱归位效果
针对你提到的原jQuery实现的问题(首字母未真正打乱、文本宽度变化),以下是贴近示例效果的纯原生JS方案:
核心改进点
- 每个字符独立拆分到固定宽度容器中,彻底解决宽度变化问题
- 所有字符都会参与随机打乱,包括首字母
- 字符动画加入错落延迟,更贴近示例的流畅效果
- 纯原生JS实现,无需依赖jQuery
完整代码实现
HTML
<ul> <li> <a class="shuffle" href="#">shuffle</a> </li> <li> <a class="shuffle" href="#">texts</a> </li> <li> <a class="shuffle" href="#">hover</a> </li> </ul>
CSS
body { font-family: helvetica; font-size: 16px; padding: 48px; } a { color: black; text-decoration: none; } ul { list-style: none; margin: 0; padding: 0; } li { display: inline-block; margin: 0 16px 8px 0; } /* 字符容器:固定宽度,确保文本整体宽度不变 */ .shuffle .char { display: inline-block; text-align: center; /* 非等宽字体可注释掉下面的ch单位,改用JS计算的精确宽度 */ width: 1ch; }
JavaScript
document.addEventListener('DOMContentLoaded', () => { const shuffleElements = document.querySelectorAll('.shuffle'); const animationSpeed = 50; // 字符替换间隔(毫秒) const shuffleCount = 8; // 每个字符打乱次数,之后恢复原字符 const staggerDelay = 20; // 字符动画错落延迟(毫秒) // 生成随机小写字母 const getRandomChar = () => { const charPool = 'abcdefghijklmnopqrstuvwxyz'; return charPool[Math.floor(Math.random() * charPool.length)]; }; // 预处理:将文本拆分为单个字符的span容器 shuffleElements.forEach(el => { const originalText = el.textContent.trim(); // 非等宽字体用这段代码计算精确宽度(注释掉上面CSS的width:1ch) /* const tempSpan = document.createElement('span'); tempSpan.style.visibility = 'hidden'; tempSpan.style.position = 'absolute'; document.body.appendChild(tempSpan); */ el.innerHTML = originalText.split('').map(char => { /* tempSpan.textContent = char; const charWidth = tempSpan.offsetWidth + 'px'; */ return `<span class="char" data-original="${char}">${char}</span>`; // 非等宽字体替换为下面的return // return `<span class="char" data-original="${char}" style="width: ${charWidth}">${char}</span>`; }).join(''); // document.body.removeChild(tempSpan); }); // 绑定悬停事件 shuffleElements.forEach(el => { let activeTimers = []; // 存储定时器,用于清理 el.addEventListener('mouseenter', () => { // 清除之前的定时器,避免动画叠加 activeTimers.forEach(timer => clearInterval(timer)); activeTimers = []; const charSpans = el.querySelectorAll('.char'); charSpans.forEach((span, index) => { const originalChar = span.dataset.original; let currentShuffleCount = 0; const timer = setInterval(() => { if (currentShuffleCount >= shuffleCount) { span.textContent = originalChar; clearInterval(timer); return; } // 随机替换字符 span.textContent = getRandomChar(); currentShuffleCount++; }, animationSpeed + (index * staggerDelay)); // 错落延迟,增强层次感 activeTimers.push(timer); }); }); // 鼠标离开时立即恢复原文本并清理定时器 el.addEventListener('mouseleave', () => { activeTimers.forEach(timer => clearInterval(timer)); activeTimers = []; el.querySelectorAll('.char').forEach(span => { span.textContent = span.dataset.original; }); }); }); });
自定义参数说明
animationSpeed:控制字符替换的快慢,值越小动画越快shuffleCount:控制每个字符打乱的次数,值越大打乱时间越长staggerDelay:控制字符动画的错落间隔,值越大错落感越明显
内容的提问来源于stack exchange,提问作者user1406440
相关产品推荐
相关产品推荐

