利用Vue 3的响应式系统实现实时物理模拟

时间:2025-9-28    作者:悬浮的青春    分类: javascript


在Web开发领域,Vue 3的响应式系统通常用于数据绑定和UI更新,但它的潜力远不止于此。本文将探索如何通过Vue 3的reactive()和computed()实现浏览器内的牛顿力学模拟,让DOM元素遵循物理规律运动,为交互设计注入全新维度。
一、为什么选择Vue 3做物理模拟?
精细的依赖追踪
effect()可精确捕捉速度、加速度等物理量的变化关系
计算属性优势
computed自动缓存动能(1/2mv²)、势能(mgh)等衍生量
性能优化空间
通过markRaw跳过非响应式对象(如碰撞检测器)的代理

二、核心实现方案

2.1 物理实体建模

const ball = reactive({ mass: 10, position: { x: 0, y: 300 }, // 初始位置 velocity: { x: 2, y: 0 }, acceleration: { x: 0, y: 9.8 } // 重力加速度 })

2.2 运动积分器(Motion Integrator)

watchEffect(() => { // 欧拉积分法计算位移 ball.position.x += ball.velocity.x deltaTime ball.position.y += ball.velocity.y deltaTime // 更新速度 ball.velocity.x += ball.acceleration.x deltaTime ball.velocity.y += ball.acceleration.y deltaTime })

2.3 边界碰撞检测

watch([() => ball.position.y, () => ball.velocity.y], ([y, vy]) => { if (y > canvasHeight - radius) { ball.position.y = canvasHeight - radius ball.velocity.y *= -0.8 // 弹性系数 } })

  1. 简易抛物线运动模拟‌
    利用Vue 3的响应式系统和requestAnimationFrame实现基础运动学:

// 组件内代码
const projectile = reactive({
x: 0,
y: 0,
vx: 5,
vy: -10,
gravity: 0.2,
update() {
this.x += this.vx
this.vy += this.gravity
this.y += this.vy
if (this.y > 0) requestAnimationFrame(this.update)
}
})
onMounted(() => projectile.update())
特点:

纯数学公式计算位置变化
通过响应式数据驱动DOM元素运动

  1. 碰撞检测与反弹效果‌
    基于Canvas 2D API和向量运算:

const balls = reactive(Array(5).fill().map(() => ({
x: Math.random() 300,
y: Math.random()
150,
r: 10 + Math.random() 10,
vx: (Math.random() - 0.5)
4,
vy: (Math.random() - 0.5) 4,
update() {
// 边界碰撞检测
if (this.x + this.r > 300 || this.x - this.r < 0) this.vx
= -0.9
if (this.y + this.r > 150 || this.y - this.r < 0) this.vy *= -0.9
this.x += this.vx
this.y += this.vy
}
})))

function animate() {
ctx.clearRect(0, 0, 300, 150)
balls.forEach(ball => {
ball.update()
ctx.beginPath()
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2)
ctx.fill()
})
requestAnimationFrame(animate)
}

  1. 弹簧质点系统模拟‌
    实现胡克定律的简化版本:

const spring = reactive({
mass: 10,
k: 0.5, // 弹性系数
damping: 0.99,
position: 100,
velocity: 0,
anchor: 50,
update() {
const force = -this.k (this.position - this.anchor)
const acceleration = force / this.mass
this.velocity += acceleration
this.velocity
= this.damping
this.position += this.velocity
}
})

watchEffect(() => {
spring.update()
cubeStyle.value = { transform: translateX(${spring.position}px) }
})
技术实现要点‌
动画循环‌:通过requestAnimationFrame实现60fps流畅动画
物理模型简化‌:
运动学公式替代完整物理引擎
离散时间步长模拟连续物理过程
性能优化‌:
使用shallowRef减少响应式开销
Canvas 2D渲染替代DOM操作
这些方案适用于教育演示或轻量级交互场景,复杂物理效果仍需Cannon.js等专业引擎

WRITTEN BY

avatar