账号密码登录
微信安全登录
微信扫描二维码登录

登录后绑定QQ、微信即可实现信息互通

手机验证码登录
找回密码返回
邮箱找回 手机找回
注册账号返回
其他登录方式
分享
  • 收藏
    X
    手机滚动-如何实现惯性滚动
    34
    0

    手机惯性滚动时应该怎么计算速度,以及之后速度怎么递减等问题

    因为要做一个手机端的滚动插件,所以想模拟出手机原生的惯性滚动,就是手指快速滑动后,手机页面在手指抬起来之后,依然会滚动一段距离的效果。

    现在我尝试了两种方法
    1、在手指start与end之间时间少于300ms时,根据手指移动距离得出需要继续滚动的长度,在end之后通过transition与top实现动画效果
    2、在手指end之后通过手指的移动距离与使用时间计算平局速度,如果使用时间少于300ms,则通过requestAnimationFrame循环调用一个每次都递减速度的函数,当速度很小时跳出函数循环。在函数中每一次都设置一次top值,因为requestAnimationFrame间隔很短,大概之后16ms左右,以实现效果

    第一种方法代码

    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalabel=no"/>
        <meta charset="utf-8"/>
        <title>移动手指事件滚动</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            .container {
                position: relative;
                margin: 50px;
                width: calc(100% - 100px);
                height: 400px;
                border: 1px solid green;
                box-sizing: border-box;
                overflow: hidden;
            }
            .container .scroll {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                transition: all 160ms ease-out;
            }
            .container p {
                margin: 0 auto 10px;
                width: 80%;
                height: 80px;
                border: 1px solid yellow;
            }
            .container .scroll:after {
                content: '';
                display: block;
                clear: both;
            }
    
            .container .barBox {
                position: absolute;
                right: 2px;
                top: 2px;
                width: 3px;
                height: calc(100% - 4px);
                background: rgba(100, 200, 100, 0.3);
            }
            .container .barBox .bar {
                position: absolute;
                top: 0;
                right: 0;
                height: 0;
                width: 100%;
                background: #ccc;
                transition: all 160ms ease-out;
            }
        </style>
    </head>
    <body>
        <div class="container" id="container">
            <div class="scroll">
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
            </div>
            <div class="barBox" id="barBox">
                <div class="bar"></div>
            </div>
        </div>
        <script>
            var oContainer = document.getElementById('container');
            var oScroll = oContainer.children[0];
            var oBarBox = document.getElementById('barBox');
            var oBar = oBarBox.children[0];
    
            // 盒子尺寸
            var iWrapperH = numberPx(getStyle(oContainer, 'height'));
            var iScrollH = numberPx(getStyle(oScroll, 'height'));
            var iBarBoxH = numberPx(getStyle(oBarBox, 'height'));
            var iBarH = iWrapperH / iScrollH * iBarBoxH;
    
            // 初始状态
            setStyle(oBar, {
                height: iBarH + 'px'
            })
    
            // 参数
            var startTime = 0;
            var endTime = 0;
            var isMove = false;
            var iScrollTop = 0;
            var iBarTop = 0;
    
            
            var endTimeout = null;
    
            oContainer.addEventListener('touchstart', function (e) {
                startTime = new Date().getTime();
    
                var startY = e.targetTouches[0].clientY;
                var startTop = numberPx(getStyle(oScroll, 'top'));
                var endY = startY;
                var endTop = startTop;
    
                setStyle(oScroll, {
                    top: startTop + 'px'
                })
                setStyle(oBar, {
                    top: -startTop / iScrollH * iBarBoxH + 'px'
                })
    
                var moveFn = function (e) {
                    isMove = true;
                    var nowY = e.targetTouches[0].clientY;
                    var nowTop = startTop;
    
                    endY = nowY;
                    
                    var moveY = nowY - startY;
                    nowTop += moveY;
                    endTop = nowTop;
                    iScrollTop = nowTop > 0 ? 0 : (nowTop < iWrapperH - iScrollH ? iWrapperH - iScrollH : nowTop);
                    iBarTop = -iScrollTop / iScrollH * iBarBoxH;
    
                    setStyle(oScroll, {
                        top: iScrollTop + 'px'
                    })
                    setStyle(oBar, {
                        top: iBarTop + 'px'
                    })
                }
    
                var endFn = function (e) {
                    endTime = new Date().getTime();
    
                    if ( endTime - startTime <= 200 && isMove ) {
                        var moveY = endY - startY;
                        var iScale = 1;
                        var iTime = 300;
                        if ( Math.abs(moveY) <= 100 ) {
                            iScale = 1;
                            iTime = 300;
                        } else if ( Math.abs(moveY) <= 200 ) {
                            iScale = 2;
                            iTime = 500;
                        } else {
                            iScale = 3;
                            iTime = 700;
                        }
                        moveY = moveY * iScale;
    
                        endTop += moveY;
                        iScrollTop = endTop > 0 ? 0 : (endTop < iWrapperH - iScrollH ? iWrapperH - iScrollH : endTop);
                        iBarTop = -iScrollTop / iScrollH * iBarBoxH;
    
                        setStyle(oScroll, {
                            transition: 'all ' + iTime + 'ms ease-out',
                            top: iScrollTop + 'px'
                        })
                        setStyle(oBar, {
                            transition: 'all ' + iTime + 'ms ease-out',
                            top: iBarTop + 'px'
                        })
                        clearTimeout(endTimeout);
                        endTimeout = setTimeout(function () {
                            setStyle(oScroll, {
                                transition: 'all 160ms ease-out'
                            })
                            setStyle(oBar, {
                                transition: 'all 160ms ease-out',
                            })
                        }, 500);
                    }
                    isMove = false;
    
                    document.documentElement.removeEventListener('touchmove', moveFn);
                    oContainer.removeEventListener('touchend', endFn);
                }
    
                document.documentElement.addEventListener('touchmove', moveFn);
                oContainer.addEventListener('touchend', endFn);
            })
    
            function getStyle (obj, name) {
                if(window.getComputedStyle) {
                    return getComputedStyle(obj, null)[name];
                } else {
                    return obj.currentStyle[name];
                }
            }
            function setStyle (obj, oStyle) {
                for(var i in oStyle) {
                    obj.style[i] = oStyle[i];
                }
            }
               function numberPx (num) {
                   return Number(num.split('px')[0]);
               }
    
        </script>
    </body>
    </html>

    第二种代码

    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalabel=no"/>
        <meta charset="utf-8"/>
        <title>移动手指事件滚动使用速度</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            .container {
                position: relative;
                margin: 50px;
                width: calc(100% - 100px);
                height: 400px;
                border: 1px solid green;
                box-sizing: border-box;
                overflow: hidden;
            }
            .container .scroll {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
            }
            .container p {
                margin: 0 auto 10px;
                width: 80%;
                height: 80px;
                border: 1px solid yellow;
            }
            .container .scroll:after {
                content: '';
                display: block;
                clear: both;
            }
    
            .container .barBox {
                position: absolute;
                right: 2px;
                top: 2px;
                width: 3px;
                height: calc(100% - 4px);
                background: rgba(100, 200, 100, 0.3);
            }
            .container .barBox .bar {
                position: absolute;
                top: 0;
                right: 0;
                height: 0;
                width: 100%;
                background: #ccc;
            }
        </style>
    </head>
    <body>
        <div class="container" id="container">
            <div class="scroll">
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
            </div>
            <div class="barBox" id="barBox">
                <div class="bar"></div>
            </div>
        </div>
        <script>
            var oContainer = document.getElementById('container');
            var oScroll = oContainer.children[0];
            var oBarBox = document.getElementById('barBox');
            var oBar = oBarBox.children[0];
    
            // 盒子尺寸
            var iWrapperH = numberPx(getStyle(oContainer, 'height'));
            var iScrollH = numberPx(getStyle(oScroll, 'height'));
            var iBarBoxH = numberPx(getStyle(oBarBox, 'height'));
            var iBarH = iWrapperH / iScrollH * iBarBoxH;
    
            // 初始状态
            setStyle(oBar, {
                height: iBarH + 'px'
            })
    
            // 参数
            var startTime = 0;
            var endTime = 0;
            var pastTime = 0;    // 过去一次的时间
            var nowTime = 0;    // 当前移动的时间
            var isMove = false;
            var iBarTop = 0;
    
        
            var timer = true;
    
            oContainer.addEventListener('touchstart', function (e) {
                startTime = new Date().getTime();
    
                pastTime = startTime;
    
                var startY = e.targetTouches[0].clientY;
                var startTop = numberPx(getStyle(oScroll, 'top'));
                var endY = startY;
                var endTop = startTop;
    
                timer = false;
    
                var moveFn = function (e) {
                    isMove = true;
                    var nowY = e.targetTouches[0].clientY;
                    var nowTop = startTop;
                    endY = nowY;
                    
                    var moveY = nowY - startY;
                    nowTop += moveY;
                    endTop = nowTop = getPos(nowTop);
    
                    setStyle(oScroll, {
                        top: nowTop + 'px'
                    })
                    setStyle(oBar, {
                        top: getBarTop(nowTop) + 'px'
                    })
                }
    
                var endFn = function (e) {
                    endTime = new Date().getTime();
    
                    var speed = (endY - startY) / (endTime - startTime);
    
                    if ( endTime - startTime <= 300 && isMove ) {
                        
                        speed *= 16;
    
                        var f = 0,
                            top = endTop;
    
                        timer = true;
    
                        show();
                        function show () {
    
                            timer && requestAnimationFrame(show);
    
                            f =  Math.min(Math.abs(speed) / 10, 0.5); //重点
                            if( speed > 0.2 ) {
                                speed -= f
                            } else if(speed < -0.2){
                                speed += f
                            } else {
                                timer = false
                                speed = 0
                                return
                            }
                            
                            top += speed;
                            if ( top > 0 || top < iWrapperH -iScrollH ) {
                                timer = false
                                speed = 0
    
                                setStyle(oScroll, {
                                    top: getPos(top) + 'px'
                                })
                                setStyle(oBar, {
                                    top: getBarTop(getPos(top)) + 'px'
                                })
                                return
                            }
                            setStyle(oScroll, {
                                top: top + 'px'
                            })
                            setStyle(oBar, {
                                top: getBarTop(top) + 'px'
                            })
                        }
    
                    }
                    isMove = false;
    
                    document.documentElement.removeEventListener('touchmove', moveFn);
                    document.documentElement.removeEventListener('touchend', endFn);
                }
    
                document.documentElement.addEventListener('touchmove', moveFn);
                document.documentElement.addEventListener('touchend', endFn);
            })
    
    
            function getPos (num) {
                return num >= 0 ? 0 : (num <= iWrapperH - iScrollH ? iWrapperH - iScrollH : num);
            }
    
            function getBarTop (num) {
                return -num / iScrollH * iBarBoxH;
            }
    
            function getStyle (obj, name) {
                if(window.getComputedStyle) {
                    return getComputedStyle(obj, null)[name];
                } else {
                    return obj.currentStyle[name];
                }
            }
            function setStyle (obj, oStyle) {
                for(var i in oStyle) {
                    obj.style[i] = oStyle[i];
                }
            }
               function numberPx (num) {
                   return Number(num.split('px')[0]);
               }
    
        </script>
    </body>
    </html>

    可以看看原生的效果

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalabel=no">
        <title>苹果移动效果</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            .container {
                position: relative;
                margin: 50px;
                width: calc(100% - 100px);
                height: 400px;
                border: 1px solid green;
                box-sizing: border-box;
                overflow: auto;
            }
            .container p {
                margin: 0 auto 10px;
                width: 80%;
                height: 80px;
                border: 1px solid yellow;
            }
        </style>
    </head>
    <body>
        <div class="container" id="container">
            <div class="scroll">
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
                <p style="border-color: green;"></p><p style="border-color: yellow;"></p><p style="border-color: #932132;"></p>
                <p style="border-color: #00007f;"></p><p style="border-color: red;"></p><p style="border-color: #432892;"></p>
                <p style="border-color: #007f00;"></p><p style="border-color: blue;"></p><p style="border-color: green;"></p>
                <p style="border-color: #7f0000;"></p><p style="border-color: #003947;"></p><p style="border-color: #cccc33;"></p>
            </div>
        </div>
    </body>
    </html>

    虽然现在看起来可以滚动了,但是感觉距离原生的惯性滚动、以及iScroll、better-scroll等的效果差的还是挺远的。看他们的源码,真是找不到哪儿是哪儿的东西,希望懂的大佬们,能够指点指点我!!!

    0
    打赏
    收藏
    点击回答
    您的回答被采纳后将获得:提问者悬赏的 10 元积分
        全部回答
    • 0
    • 在手机App或移动网页开发中,惯性滚动(也叫弹性滚动或者自由滚动)是一种模拟真实物理世界的滚动效果,用户在触摸屏上滑动后,内容区域不会立即停止滚动,而是会因为“惯性”继续滚动一段距离,给用户带来更自然、流畅的交互体验。 以下是实现惯性滚动的一些方法: 1. **对于原生App开发:** - iOS 使用 UIKit 框架,UIScrollView 类已经内置了惯性滚动功能,只需要设置 `scrollEnabled = true` 即可。 - Android 使用 RecyclerView 或 ScrollView 时,其滚动默认具有一定的惯性效果。如果需要增强此效果,可以调整 OverScroller 的摩擦系数等参数。 2. **对于H5网页开发:** - CSS3中的`-webkit-overflow-scrolling: touch;`属性可以开启iOS设备上的惯性滚动。例如: ```css .scrollable { overflow-y: auto; -webkit-overflow-scrolling: touch; } ``` - 对于Android和非iOS设备,由于浏览器原生并不支持这一特性,通常需要借助iScroll、better-scroll、swiper等第三方库来实现类似的效果。 3. **对于React Native等跨平台开发框架:** - React Native的ScrollView组件本身就支持惯性滚动,只需正常使用即可。 请注意,不同的开发环境和框架可能有不同的实现方式,但基本原理都是通过模拟物理世界中的滚动摩擦力、速度衰减等特性来实现滚动视图的惯性效果。
    更多回答
    网站公告
    扫一扫访问手机版
    • 回到顶部
    • 回到顶部