JavaScript运动之缓冲运动

缓冲运动

逐渐变慢,最后停止
距离越远,速度越大
  1. 速度由距离决定
  2. 速度 = (目标值 - 当前值)/ 缩放系数
例子:缓冲菜单
- Bug:速度取整
- 跟随页面滚动的缓冲侧边栏
1.    潜在问题:目标值不是整数时
速度和距离成正比

<html>
<head>
    <title>title>
    <style type="text/css">
        #div1 {
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 50px;
        }
        #div2 {
            width: 1px;
            height: 300px;
            position: absolute;
            left: 300px;
            top: 0;
            background: black;
        }
    style>
head>
<body>
    <div id="div1">div>
    <div id="div2">div>
    <input type="button" value="Start" onclick="startMove()" />
    <script type="text/javascript">
        var oDiv = document.getElementById('div1');
        function startMove() {
            setInterval(function() {
                //随着距离的减小,速度也越来越小,符合缓冲的要求,用距离(时刻变化)的十分之一
                var speed = (300 - oDiv.offsetLeft) / 10;
                oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                document.title = oDiv.offsetLeft + ', ' + speed;
            }, 30);
        }
    script>
body>
html>
  • ##### 最后在title上发现“291, 0.9”,也就是物体向右缓冲运动到291px的位置停下,最后时刻有一刻距离还剩9px,速度也就是0.9px,然后滑动向着291.9px的目标前进,但是px是最小的单位,291.9px,计算机就认为是291px,所以,也就永远停在291的位置了,还到不了300的最终位置

Math

Math.ceil(3.2) ==> 4
Math.ceil(-9.7) ==> -9
Math.floor(5.98) ==> 5
所以,speed采用ceil方法向上取整即可,最后能跑到300的位置,分毫不差
function startMove() {
    setInterval(function() {
        //随着距离的减小,速度也越来越小,符合缓冲的要求,用距离(时刻变化)的十分之一
        var speed = (300 - oDiv.offsetLeft) / 10;
        speed = Math.ceil(speed);//划重点
        oDiv.style.left = oDiv.offsetLeft + speed + 'px';
        document.title = oDiv.offsetLeft + ', ' + speed;
    }, 30);
}

这样就完了吗?没有!如果物体左移,也就是比如把div1的left的初始left由0 –> 600,那么,依旧不能分毫无差,最后看title为“309, 0”,实际上,速度为-0.9,(下一刻向着目标308.1px的位置移动),此时Math.ceil()已经不好用了,得用Math.floor();

#div1 {
    width: 100px;
    height: 100px;
    background: red;
    position: absolute;
    left: 600px;/*0 --> 600*/
    top: 50px;
}
function startMove() {
    setInterval(function() {
        var speed = (300 - oDiv.offsetLeft) / 10;
        speed = Math.floor(speed);//划重点
        oDiv.style.left = oDiv.offsetLeft + speed + 'px';
        document.title = oDiv.offsetLeft + ', ' + speed;
    }, 30);
}
综上所述:如果正向移动,为了让物体迈过那个不足1的坎,要帮助小数颠颠脚够着更大的整数(0.2 –>1,ceil),如果负向移动,为了让物体迈过不足-1的坎,要帮小数颠颠脚够着更小(绝对值更大)的整数(-0.1 –> -1, floor)
offsetWidth = width + border + padding;
offsetWidth = height + border + padding;
offsetWidth = width + border + padding;
function startMove() {
    setInterval(function() {
        var speed = (300 - oDiv.offsetLeft) / 10;
        speed = speed > 0 ? Math.ceil(speed) : Match.floor(speed);
        oDiv.style.left = oDiv.offsetLeft + speed + 'px';
        document.title = oDiv.offsetLeft + ', ' + speed;
    }, 30);
}

总结:但凡是用了缓冲运动的一定要记得速度取整,缓冲也就是速度不停的变化。


缓冲菜单

要求:在右下角有个红色div,无论浏览器怎么滚动,始终落脚在右下角
注意几个概念:
offsetWidth = width + border + padding;
offsetHeight = width + border + padding;
document.documentElement.scrollHeight:
    内容可视区域的高度,真正展示网页内容的高度,客户端的界面要跑除,如果你用鼠标调节浏览器窗口的大小,那么这个值会变化。
document.documentElement.scrollHeight:就是3500px,上面已经设置了
网页被卷去的高:document.body.scrollTop 
兼容:
var top = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
综上所述:
    在我们要获取文档实际高度时,最好用document.documentElement.scrollHeight
  在我们要获取视口实际高度时,用document.documentElement.clientHeight

<html>
<head>
    <title>title>
    <style type="text/css">
        * {
            padding: 0;
            margin: 0;
        }
        #div1 {
            width: 100px;
            height: 150px;
            background: red;
            position: absolute;
            bottom: 0;
            right: 0;
            border: 3px solid blue;
            padding: 20px;
        }
    style>
head>
<body style="height: 3500px;">
    <div id="div1">div>
    <div id="div2">div>
    <script type="text/javascript">
        window.onscroll = function() {
            var oDiv = document.getElementById('div1');
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            oDiv.style.top = document.documentElement.clientHeight - oDiv.offsetHeight + scrollTop + 'px';
        };
    script>
body>
html>
上面这段代码就可以让红色物体div紧紧 ‘fix’到页面的右下角,但是,你滚动网页的时候发现div为了努力的紧跟右下角,很费力的在抖动,看起来很不自然,为了看起来自然,需要自写一个运动框架,不让他硬生生的跟着走,而是慢慢的缓缓的缓冲运动。

<html>
<head>
    <title>title>
    <style type="text/css">
        * {
            padding: 0;
            margin: 0;
        }
        #div1 {
            width: 100px;
            height: 150px;
            background: red;
            position: absolute;
            bottom: 0;
            right: 0;
            border: 3px solid blue;
            padding: 20px;
        }
    style>
head>
<body style="height: 3500px;">
    <div id="div1">div>
    <div id="div2">div>
    <script type="text/javascript">
        window.onscroll = function() {
            var oDiv = document.getElementById('div1');
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            //oDiv.style.top = document.documentElement.clientHeight - oDiv.offsetHeight + scrollTop + 'px';
            startMove(document.documentElement.clientHeight - oDiv.offsetHeight + scrollTop);
        };

        var timer = null;
        function startMove(iTarget) {
            var oDiv = document.getElementById('div1');
            clearInterval(timer);
            timer = setInterval(function() {
                var speed = (iTarget - oDiv.offsetTop)/6;
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                if (oDiv.offsetTop == iTarget) {
                    clearInterval(timer);
                } else {
                    oDiv.style.top = oDiv.offsetTop + speed + 'px';
                }
            }, 30);
        }
    script>
body>
html>

对联悬浮框

不同上边案例悬浮在右下角,而是‘fix’到右边正中间位置


<html>
<head>
    <title>title>
    <style type="text/css">
        * {
            padding: 0;
            margin: 0;
        }
        #div1 {
            width: 100px;
            height: 150px;
            background: red;
            position: absolute;
            bottom: 0;
            right: 0;
            border: 3px solid blue;
            padding: 20px;
        }
    style>
head>
<body style="height: 3500px;">
    <div id="div1">div>
    <div id="div2">div>
    <script type="text/javascript">
        window.onscroll = function() {
            var oDiv = document.getElementById('div1');
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            //其实仅仅就是参数iTarget的计算变了一下
            startMove((document.documentElement.clientHeight - oDiv.offsetHeight) / 2 + scrollTop);
        };

        var timer = null;
        function startMove(iTarget) {
            var oDiv = document.getElementById('div1');
            clearInterval(timer);
            timer = setInterval(function() {
                var speed = (iTarget - oDiv.offsetTop)/6;
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                if (oDiv.offsetTop == iTarget) {
                    clearInterval(timer);
                } else {
                    oDiv.style.top = oDiv.offsetTop + speed + 'px';
                }
            }, 30);
        }
    script>
body>
html>

代码写完了,发现红色div在右边中间以很小的振幅在不同的抖动,问题就出在除以2这里,除以2就可能出现小数的可能性

startMove((document.documentElement.clientHeight - oDiv.offsetHeight) / 2 + scrollTop);
改为:
startMove(parseInt(document.documentElement.clientHeight - oDiv.offsetHeight) / 2 + scrollTop));

你可能感兴趣的:(前端)