Background: The scrollTop of div needs to be changed in the process of doing the project a few days ago, requiring the movement process to be similar to IOS Webview visual area ceiling animation, first fast and then slow.
Analysis:
- css can't set offsetTop. JS needs to change offsetTop dynamically.
- Faster and slower animation means that scrollTop changes are slower and slower
- The total distance of the mobile is scrollTop.
- Events are controlled in two seconds, less than 1 s on a screen and more than 2 s on a screen.
- Speed? Distance?? The integral of velocity in time equals distance???? Definite integral!!!!
Conjecture function:
What function is decreasing?
What functions do definite integrals do well? In other words, the original function is easy to find.
What function scope contains 0 (because it needs to start at 0)
What function is the integral of scrollTop in 0-2S?
Blind guess y = 1/x;
Scope does not contain 0???? Shift one unit to the right??? Left plus right minus, up plus down minus!!! Dundun Teaching of Haha Haha High Mathematics Teacher==
y = 1 / (x + 1);
Y = 1 / x + 1; must the integral in 0-2s be scrollTop???
Need a coefficient?????
y = K / (x + 1) ;
How can we get this coefficient?
y = K / (x + 1);
The integral of y on 0 - 2 = scrollTop;
The original function f(x) = Math.log(x) + c of y = 1/x is constant.
By analogy, the original function f (x) = Math. log (x + 1) + C of y = K / x + 1 is obtained, and C is a constant.
The final implementation code is as follows:
optimize performance
setInterval achieves this effect only by using 20ms as the time point for offset changes
Higher optimization???? Request AnimFrame!!! MDN requestAnimationFrame
Core idea: Get the interval between two recursive events??? new Date().getTime() - startTime
The final realization is as follows:
Complete code
<!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>test 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; // Total time 2000 ms const allX = 2000 / timeStep; let startX = 0; // coefficient const ratio = scrollTop / Math.log(allX + 1); // Definite integrals are available 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; // Total time 2000 ms const allX = 2000 / timeStep; let startX = 0; // coefficient const ratio = scrollTop / Math.log(allX + 1); // Definite integrals are available 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"> //Begin 123 123 123 campaign </div> </body> </html>
This is fast and slow animation, and other animation solutions are the same.
Core:
Find function, do integral!!! Find function, do integral!!! Find function, do integral!!!
Finally, if you can use css to achieve, less JS