页面抖动:setInterval(() => document.body.style.marginLeft = (Math.random()*20-10)+'px', 50);
页面抖动:setInterval(() => document.body.style.marginLeft = (Math.random()*20-10)+'px', 50);
页面抖动是一种常见的视觉特效,通过快速改变元素位置产生震动效果。setInterval
配合随机数生成器可以轻松实现这种动态变化。下面这段代码每50毫秒随机调整body
元素的左外边距,产生左右摇晃的视觉效果:
setInterval(() => {
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
}, 50);
实现原理分析
这段代码的核心在于三个关键点:定时器、随机数计算和样式修改。Math.random()
生成0到1之间的浮点数,乘以20后范围变为0-20,减去10得到-10到10的范围。这样每次执行都会产生不同的负值或正值:
// 随机数生成过程分解
const randomValue = Math.random(); // 0 ≤ x < 1
const scaledValue = randomValue * 20; // 0 ≤ x < 20
const finalValue = scaledValue - 10; // -10 ≤ x < 10
定时器间隔50毫秒(即每秒20帧)保证了动画的流畅性。这个频率接近人眼的视觉暂留极限,能产生连续动画效果而不会显得卡顿。
实际应用场景
这种抖动效果虽然简单,但在特定场景下非常实用:
- 错误提示增强:表单验证失败时让输入框轻微震动
function shakeElement(element) {
let count = 0;
const interval = setInterval(() => {
element.style.transform = `translateX(${Math.random() * 6 - 3}px)`;
if(++count >= 10) clearInterval(interval);
}, 50);
}
- 游戏特效:角色受到攻击时的受击反馈
// 游戏角色抖动示例
const character = document.getElementById('game-character');
function takeDamage() {
const originalPosition = character.getBoundingClientRect().left;
const interval = setInterval(() => {
character.style.left = originalPosition + (Math.random() * 10 - 5) + 'px';
}, 30);
setTimeout(() => clearInterval(interval), 300);
}
- 注意力引导:吸引用户注意特定界面元素
function highlightElement(element) {
const originalMargin = element.style.marginLeft;
const interval = setInterval(() => {
element.style.marginLeft = (Math.random() * 15 - 7.5) + 'px';
}, 40);
// 3秒后停止抖动
setTimeout(() => {
clearInterval(interval);
element.style.marginLeft = originalMargin;
}, 3000);
}
性能优化方案
原始实现虽然简单,但存在性能隐患。以下是几种优化方式:
- 使用requestAnimationFrame替代setInterval
function startShake() {
let lastTime = 0;
function shake(timestamp) {
if(timestamp - lastTime > 50) {
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
lastTime = timestamp;
}
requestAnimationFrame(shake);
}
requestAnimationFrame(shake);
}
- CSS动画方案(性能更优)
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake-element {
animation: shake 0.5s linear infinite;
}
- 限制抖动范围避免布局重排
// 使用transform代替margin修改
setInterval(() => {
document.body.style.transform = `translateX(${Math.random() * 20 - 10}px)`;
}, 50);
高级变体实现
基于基础抖动可以开发更复杂的效果:
- 三维抖动(增加Y轴和Z轴变化)
setInterval(() => {
const x = Math.random() * 10 - 5;
const y = Math.random() * 8 - 4;
document.body.style.transform = `translate3d(${x}px, ${y}px, 0)`;
}, 50);
- 衰减抖动(幅度逐渐减小)
function decayingShake(element, duration = 1000) {
const startTime = Date.now();
const maxOffset = 15;
function update() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
const currentOffset = maxOffset * (1 - progress);
if(progress < 1) {
element.style.transform = `translateX(${(Math.random() * 2 - 1) * currentOffset}px)`;
requestAnimationFrame(update);
} else {
element.style.transform = '';
}
}
update();
}
- 节奏抖动(配合音乐节拍)
// 假设有音频分析数据
function beatShake(analyser) {
analyser.getByteFrequencyData(frequencyData);
const bass = frequencyData[0] / 255;
document.body.style.transform = `translateX(${bass * 20 - 10}px)`;
requestAnimationFrame(() => beatShake(analyser));
}
浏览器兼容性考虑
不同浏览器对高频样式修改的处理存在差异:
- 老版本IE限制:
// IE9及以下需要特殊处理
if(document.documentMode && document.documentMode < 10) {
// 使用更简单的抖动方式
let toggle = false;
setInterval(() => {
document.body.style.marginLeft = toggle ? '5px' : '-5px';
toggle = !toggle;
}, 100);
} else {
// 现代浏览器使用标准实现
setInterval(() => {
document.body.style.transform = `translateX(${Math.random() * 20 - 10}px)`;
}, 50);
}
- 移动端优化:
// 检测触摸设备减少抖动幅度
const isTouchDevice = 'ontouchstart' in window;
const amplitude = isTouchDevice ? 5 : 10;
setInterval(() => {
document.body.style.transform = `translateX(${Math.random() * amplitude * 2 - amplitude}px)`;
}, 50);
调试技巧
开发时可能需要监控抖动效果:
- 性能分析:
// 记录执行时间
setInterval(() => {
const start = performance.now();
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
console.log('执行耗时:', performance.now() - start);
}, 50);
- 振幅可视化:
// 添加调试面板
const debugPanel = document.createElement('div');
debugPanel.style.position = 'fixed';
debugPanel.style.bottom = '0';
document.body.appendChild(debugPanel);
setInterval(() => {
const value = Math.random() * 20 - 10;
document.body.style.marginLeft = value + 'px';
debugPanel.textContent = `当前振幅: ${value.toFixed(2)}px`;
}, 50);
- 帧率检测:
let lastTime = performance.now();
let frameCount = 0;
setInterval(() => {
document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
frameCount++;
const now = performance.now();
if(now - lastTime >= 1000) {
console.log(`当前FPS: ${frameCount}`);
frameCount = 0;
lastTime = now;
}
}, 50);
与其他动画库的集成
可以将基础抖动效果整合到专业动画库中:
- GSAP实现:
import { gsap } from "gsap";
function gsapShake(element) {
gsap.to(element, {
x: () => Math.random() * 20 - 10,
duration: 0.05,
repeat: -1
});
}
- Anime.js版本:
import anime from 'animejs';
anime({
targets: document.body,
translateX: () => Math.random() * 20 - 10,
duration: 50,
loop: true
});
- React组件封装:
function ShakyComponent({ children, intensity = 10 }) {
const [offset, setOffset] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setOffset(Math.random() * intensity * 2 - intensity);
}, 50);
return () => clearInterval(interval);
}, [intensity]);
return (
<div style={{ transform: `translateX(${offset}px)` }}>
{children}
</div>
);
}
物理引擎模拟
更真实的抖动可以引入物理参数:
- 速度衰减模型:
let velocity = 0;
let position = 0;
const friction = 0.9;
function physicsShake() {
// 随机施加力
velocity += (Math.random() - 0.5) * 2;
// 应用物理计算
velocity *= friction;
position += velocity;
// 限制边界
if(Math.abs(position) > 15) {
position = Math.sign(position) * 15;
velocity *= -0.5;
}
document.body.style.transform = `translateX(${position}px)`;
requestAnimationFrame(physicsShake);
}
physicsShake();
- 弹簧抖动模型:
let position = 0;
let velocity = 0;
const spring = 0.1;
const damping = 0.8;
function springShake() {
// 随机目标位置
const target = Math.random() * 20 - 10;
// 弹簧物理计算
const acceleration = (target - position) * spring;
velocity += acceleration;
velocity *= damping;
position += velocity;
document.body.style.transform = `translateX(${position}px)`;
requestAnimationFrame(springShake);
}
springShake();
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn