下面是关于BOM系列第二篇之定时器requestAnimationFrame的详细讲解:
什么是定时器requestAnimationFrame
requestAnimationFrame是浏览器提供的一种类似定时器的 API,它可以让我们方便地控制动画的帧数,实现流畅的动画效果。
requestAnimationFrame的用法
setInterval和setTimeout的缺点
在讲解requestAnimationFrame之前,先看一下setInterval和setTimeout的缺点。
setInterval和setTimeout虽然可以让我们周期性地执行某些代码,但是很容易出现卡顿或者滑动不流畅的问题。因为setInterval和setTimeout的回调函数执行的时间都是不确定的,如果我们动画的渲染时间被延迟了,就会出现卡顿或者滑动不流畅的问题。
requestAnimationFrame的优点
与setInterval和setTimeout相比,requestAnimationFrame有以下几个优点:
- 执行的回调函数在下一次浏览器绘制之前执行,可以保证我们动画的渲染时间是固定的,从而避免卡顿或者滑动不流畅的问题;
- 浏览器会自动优化requestAnimationFrame的执行时间,最大化地利用浏览器资源,保证帧率的稳定性;
- 如果当前页面被隐藏或者最小化了,requestAnimationFrame会自动停止执行,从而减少不必要的资源浪费。
requestAnimationFrame的用法
requestAnimationFrame和setTimeout、setInterval的用法类似,只需要调用window.requestAnimationFrame方法,并把要执行的函数作为参数传递进去即可。
假设我们要实现一个简单的旋转动画,代码如下所示:
// animation.js
// 定义需要旋转的元素
var element = document.getElementById('rotate-element')
// 定义动画开始的时间
var startTime = null
function rotate(timestamp) {
if (!startTime) {
startTime = timestamp
}
// 计算当前时间与动画开始时间之间的时间差
var deltaTime = timestamp - startTime
// 计算旋转的角度
var angle = (deltaTime / 500) * 360
// 设置元素的旋转角度
element.style.transform = 'rotate(' + angle + 'deg)'
// 如果旋转角度小于360度,就需要继续执行动画
if (angle < 360) {
window.requestAnimationFrame(rotate)
}
}
// 开始执行动画
window.requestAnimationFrame(rotate)
代码中,我们定义了一个rotate函数,这个函数的作用是根据当前时间计算出旋转的角度,并把旋转角度应用到需要旋转的元素上。
在rotate函数中,我们使用window.requestAnimationFrame方法来递归地执行rotate函数,并且传递的参数是当前的时间戳。如果旋转的角度小于360度,就需要继续执行动画,否则动画结束。
requestAnimationFrame的兼容性
requestAnimationFrame在大部分现代浏览器中都得到了支持,但是在一些比较老的浏览器中可能不支持。为了兼容不支持requestAnimationFrame的浏览器,我们可以使用polyfill,具体实现方法可以参考下面的代码示例。
示例一:实现一个简单的滑动动画
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>滑动动画示例</title>
<style>
.container {
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
}
.content {
position: absolute;
top: 0;
left: 0;
width: 600px;
height: 300px;
background-color: #ccc;
}
</style>
</head>
<body>
<div class="container">
<div class="content"></div>
</div>
<script src="animation.js"></script>
</body>
</html>
// animation.js
var container = document.querySelector('.container')
var content = document.querySelector('.content')
var duration = 10000 // 动画的持续时间
var startTime = null // 动画起始时间
var distance = content.offsetWidth - container.offsetWidth // 需要滑动的距离
function scrollTo(timestamp) {
if (!startTime) {
startTime = timestamp
}
var deltaTime = timestamp - startTime // 计算当前时间与动画起始时间之间的时间差
var progress = deltaTime / duration // 计算当前时间进度
var scrollLeft = distance * progress // 计算当前需要滑动的距离
container.scrollLeft = scrollLeft // 设置滚动条的位置
// 如果动画没有结束,就继续执行动画
if (scrollLeft < distance) {
window.requestAnimationFrame(scrollTo)
}
}
// 开始执行动画
window.requestAnimationFrame(scrollTo)
代码中,我们定义了一个函数scrollTo来滑动容器中的内容,这个函数的作用是根据当前时间计算出滑动的距离,并通过修改滚动条的位置来实现滑动效果。
在scrollTo函数中,我们使用window.requestAnimationFrame方法来递归地执行scrollTo函数,并且传递的参数是当前的时间戳。如果动画没有结束,就需要继续执行动画。
示例二:使用requestAnimationFrame实现平滑滚动
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>平滑滚动示例</title>
<style>
.container {
height: 2000px;
overflow: auto;
}
.box {
height: 100px;
margin-bottom: 20px;
background-color: #ccc;
}
</style>
</head>
<body>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<script src="scroll.js"></script>
</body>
</html>
// scroll.js
var container = document.querySelector('.container')
var isScrolling = false // 是否正在进行滚动操作
var requestId = null // requestAnimationFrame的ID
function scrollTo(target, duration) {
if (isScrolling) {
return
}
isScrolling = true // 标记正在进行滚动操作
var start = container.scrollTop // 起始位置
var distance = target - start // 需要滚动的距离
var startTime = null // 开始时间
function scroll(timestamp) {
if (!startTime) {
startTime = timestamp
}
var deltaTime = timestamp - startTime // 当前时间与开始时间之间的时间差
var progress = deltaTime / duration // 进度比例
var scrollY = start + distance * progress // 当前滚动的位置
container.scrollTop = scrollY // 设置滚动条的位置
// 如果动画没有结束,就继续执行动画
if (progress < 1) {
requestId = window.requestAnimationFrame(scroll)
} else {
isScrolling = false // 标记结束滚动操作
}
}
requestId = window.requestAnimationFrame(scroll)
}
container.addEventListener('click', function (event) {
var target = event.target
if (target.classList.contains('box')) {
var boxTop = target.offsetTop // 目标位置
scrollTo(boxTop, 200)
}
})
代码中,我们定义了一个函数scrollTo来平滑滚动容器的内容,这个函数的作用是根据当前时间计算出滑动的位置,并通过修改滚动条的位置来实现平滑滚动效果。
我们在scrollTo函数中,使用window.requestAnimationFrame方法来递归地执行scroll函数,并且传递的参数是当前的时间戳。如果动画没有结束,就需要继续执行动画。
最后,在body容器上添加一个click事件监听器,当我们点击.box元素的时候,就会平滑滚动到目标位置。
至此,BOM系列第二篇之定时器requestAnimationFrame的完整攻略就结束了,希望对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:BOM系列第二篇之定时器requestAnimationFrame - Python技术站