飞机追随鼠标效果
实现一个小飞机一直追随鼠标移动的效果,效果如下:
上代码
let plane = document.createElement('div')
plane.style.backgroundImage = 'url(plane.png)'
plane.style.backgroundRepeat = 'no-repeat'
plane.style.backgroundSize = 'cover'
plane.style.width = '50px'
plane.style.height = '50px'
plane.style.position = 'absolute'
plane.style.top = window.innerHeight / 2 + 'px'
plane.style.left = window.innerWidth / 2 + 'px'
plane.style.transitionProperty = 'top,left'
plane.style.transitionDuration = '.5s,.5s'
plane.style.transitionTimingFunction = 'linear, linear'
document.body.style.position = 'relative'
document.body.style.height = '100vh'
document.body.appendChild(plane)
let mx = 0, my = 0, deg = 0;
let x, y;
window.addEventListener('mousemove', function (e) {
x = e.x
y = e.y
mx = e.x - plane.offsetLeft - plane.clientWidth / 2
my = e.y - plane.offsetTop - plane.clientHeight / 2
deg = Math.atan(my / mx) * (180 / Math.PI) + 45
if (mx < 0) {
deg += 180
}
})
move()
function move() {
plane.style.left = (mx > 0 ? x - plane.clientWidth : x) + 'px';
plane.style.top = (my > 0 ? y - plane.clientHeight : y) + 'px';
plane.style.transform = 'rotate(' + deg + 'deg)'
requestAnimationFrame(move)
}
plane元素我使用js创建的,样式也是通过js设置的。当然,也可以在Html中定义。
代码解释
其实这个效果的主要逻辑就是,监听鼠标的移动事件,然后改变plane相对定位的left,top到鼠标的当前坐标即可。但是其中还是有一些要点要注意。
飞机的方向根据鼠标位置不同而改变
如果我们只改变坐标位置,那么不会出现上图的效果,我们要根据鼠标移动的位置,改变plane的旋转角度。
mx,my分别是鼠标相对plane的位置移动的距离。mx就是相对于plane的x轴移动的位置,my就是y轴的。
有了mx,my那么根据下面这个图,不难发现我们能到得到偏移角度的正切值就是
然后我们可以通过Mat.atan(my/mx)
计算出的正切值,但是这个是弧度制的,通过转化为角度制(可以去看我三角函数的文章三角函数笔记),我们就得到了偏移角度。
为什么要加45°呢?是因为,我们的飞机图片原本大概就偏转了45°(如下图),再加45°,那么就是飞机头指向鼠标的角度。如果是垂直向上的飞机图片,那么就要偏转90°
代码中还有一句判断,mx<0
时,会将当前的计算的角度再加180°。这是为什么呢?这是因为在mx<0
时,相当于飞机头从向左转到向右,我们观察角度如何变化,除去本身飞机图片偏转45°加上我们修正的45°。偏转的绝对角度过程如下:0°→90°→180°,我们发现,偏转绝对角度超过了90°,我们观察的函数图像:
当超过90°时,mx
开始小于0,my>0
这时为负值,用计算的角度变成了如下图所示的角度:
此时Mat.atan(my/mx)
其实计算的角度是上图的角,而我们要得值其实是:90°+,通过换算:
,那么偏转角度=180°+。
mx
开始小于0,my<0
的情况:
其实公式是一样的:
那么为什么my<0
的时候不需要做任何处理呢?其实我们观察,my<0
时,也有两种情况:
左边这种,在mx<0
的时候已经处理了,右边这种情况因为偏转角度没有超过90°所以不需要特别处理。
requestAnimationFrame()
会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。