阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 页面抖动:setInterval(() => document.body.style.marginLeft = (Math.random()*20-10)+'px', 50);

页面抖动:setInterval(() => document.body.style.marginLeft = (Math.random()*20-10)+'px', 50);

作者:陈川 阅读数:37802人阅读 分类: JavaScript

页面抖动: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帧)保证了动画的流畅性。这个频率接近人眼的视觉暂留极限,能产生连续动画效果而不会显得卡顿。

实际应用场景

这种抖动效果虽然简单,但在特定场景下非常实用:

  1. 错误提示增强:表单验证失败时让输入框轻微震动
function shakeElement(element) {
  let count = 0;
  const interval = setInterval(() => {
    element.style.transform = `translateX(${Math.random() * 6 - 3}px)`;
    if(++count >= 10) clearInterval(interval);
  }, 50);
}
  1. 游戏特效:角色受到攻击时的受击反馈
// 游戏角色抖动示例
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);
}
  1. 注意力引导:吸引用户注意特定界面元素
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);
}

性能优化方案

原始实现虽然简单,但存在性能隐患。以下是几种优化方式:

  1. 使用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);
}
  1. 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;
}
  1. 限制抖动范围避免布局重排
// 使用transform代替margin修改
setInterval(() => {
  document.body.style.transform = `translateX(${Math.random() * 20 - 10}px)`;
}, 50);

高级变体实现

基于基础抖动可以开发更复杂的效果:

  1. 三维抖动(增加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);
  1. 衰减抖动(幅度逐渐减小)
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();
}
  1. 节奏抖动(配合音乐节拍)
// 假设有音频分析数据
function beatShake(analyser) {
  analyser.getByteFrequencyData(frequencyData);
  const bass = frequencyData[0] / 255;
  
  document.body.style.transform = `translateX(${bass * 20 - 10}px)`;
  requestAnimationFrame(() => beatShake(analyser));
}

浏览器兼容性考虑

不同浏览器对高频样式修改的处理存在差异:

  1. 老版本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);
}
  1. 移动端优化
// 检测触摸设备减少抖动幅度
const isTouchDevice = 'ontouchstart' in window;
const amplitude = isTouchDevice ? 5 : 10;

setInterval(() => {
  document.body.style.transform = `translateX(${Math.random() * amplitude * 2 - amplitude}px)`;
}, 50);

调试技巧

开发时可能需要监控抖动效果:

  1. 性能分析
// 记录执行时间
setInterval(() => {
  const start = performance.now();
  document.body.style.marginLeft = (Math.random() * 20 - 10) + 'px';
  console.log('执行耗时:', performance.now() - start);
}, 50);
  1. 振幅可视化
// 添加调试面板
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);
  1. 帧率检测
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);

与其他动画库的集成

可以将基础抖动效果整合到专业动画库中:

  1. GSAP实现
import { gsap } from "gsap";

function gsapShake(element) {
  gsap.to(element, {
    x: () => Math.random() * 20 - 10,
    duration: 0.05,
    repeat: -1
  });
}
  1. Anime.js版本
import anime from 'animejs';

anime({
  targets: document.body,
  translateX: () => Math.random() * 20 - 10,
  duration: 50,
  loop: true
});
  1. 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>
  );
}

物理引擎模拟

更真实的抖动可以引入物理参数:

  1. 速度衰减模型
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();
  1. 弹簧抖动模型
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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌