背景: 前几天在做项目的过程中需要更改div的scrollTop,要求运动过程类似IOS Webview可视区吸顶动画,先快后慢
分析:
- css不能设置offsetTop,需要JS动态更改offsetTop。
- 动画先快后慢意味着,scrollTop更改的速度越来越慢
- 移动总体的距离是scrollTop。
- 事件控制在两秒之类,小于一屏幕1s,大于一屏幕2s
- 速度??距离?? 速度在时间上的积分等于距离???? 定积分!!!!
猜想函数:
什么函数是递减的??
什么函数做定积分好做。换句话说,原函数好找??
什么函数作用域包涵0(因为需要从0时刻开始)
什么函数在0-2S的积分为scrollTop
盲猜 y = 1 / x;
作用域不包含0 ??? 向右平移一个单位 ??? 左加右减,上加下减!!!哈哈哈哈 高数老师的敦敦教导= =
y = 1 / (x + 1);
y = 1 / (x + 1); 在0-2s的积分一定是scrollTop吗 ????
需要一个系数????
y = K / (x + 1) ;
怎么求出这个系数呢??
y = K / (x + 1);
y 在 0 - 2上的积分 = scrollTop;
y = 1 / x的原函数 f(x) = Math.log(x) + c, c为常数;
类推求出 y = K / (x + 1)的原函数 f(x) = Math.log(x + 1) + c, c为常数;
最终实现代码如下:
优化性能
setInterval实现这种效果只是使用20ms作为offset更改的时间点
更高的优化 ???? requestAnimFrame!!!MDN requestAnimationFrame
核心思路: 获取两次递归的事件间隔??? new Date().getTime() - startTime
最终实现如下:
完整代码
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试scroll</title>
<style>
* {
padding: 0;
margin: 0;
}
.scroll {
height: 400px;
overflow: scroll;
width: 100px;
background-color: red;
}
.scroll div:nth-child(even) {
height: 60px;
background-color: red;
}
.scroll div:nth-child(odd) {
height: 60px;
background-color: green;
}
.button {
position: fixed;
right: 0;
top: 0;
height: 30px;
width: 100px;
background-color: red;
font-size: 12px;
line-height: 30px;
text-align: center;
}
</style>
<script>
window.addEventListener('load', () => {
const scrollDOM = document.querySelector('.scroll');
const btnDOM = document.querySelector('.button');
window.requestAnimFrame = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame;
btnDOM.addEventListener('click', () => {
console.log(scrollDOM.scrollTop);
let scrollTop = scrollDOM.scrollTop;
window.requestAnimFrame
? window.requestAnimFrame(() => requestFrameUpdateScrollTop(new Date().getTime(), scrollTop))
: setTimeUpdateScrollTop(scrollTop);
});
const requestFrameUpdateScrollTop = (startTime, scrollTop) => {
const timeStep = 20;
// 总时间 2000 ms
const allX = 2000 / timeStep;
let startX = 0;
// 系数
const ratio = scrollTop / Math.log(allX + 1);
// 定积分可得
const speed = ratio * (1 / (startX + 1));
const time = new Date().getTime();
const timeDiff = time - startTime;
startX += Math.floor(timeDiff / timeStep) + 1;
scrollTop = scrollTop - speed * startX;
scrollTop = scrollTop <= 1 ? 0 : scrollTop;
scrollDOM.scrollTop = scrollTop;
if (scrollTop > 0) {
window.requestAnimFrame(() => requestFrameUpdateScrollTop(Date.now(), scrollTop));
}
};
const setTimeUpdateScrollTop = scrollTop => {
if (this.timer) {
return;
}
const timeStep = 20;
// 总时间 2000 ms
const allX = 2000 / timeStep;
let startX = 0;
// 系数
const ratio = scrollTop / Math.log(allX + 1);
// 定积分可得
this.timer = setInterval(() => {
const speed = ratio * (1 / (startX + 1));
console.log(speed);
startX++;
scrollTop = scrollTop - speed;
scrollDOM.scrollTop = scrollTop < 0 ? 0 : scrollTop;
if (scrollTop <= 0) {
clearInterval(this.timer);
this.timer = null;
}
}, timeStep);
};
});
</script>
</head>
<body>
<div class="scroll">
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
<div>asdasd</div>
</div>
<div class="button">
开始123123123运动
</div>
</body>
</html>
这是先快后慢的动画, 其他动画的解决思路同理
核心:
找函数 ,做积分!!!
找函数 ,做积分!!!
找函数 ,做积分!!!
最后说句:如果能用css实现,少用JS
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。