6弹性势能动画

实现一个JS弹性势能动画效果代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>弹性势能动画</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        html, body {
            width: 100%;
            height: 100%;
            background: #e1e1e1;
            overflow: hidden;
        }

        #mark {
            position: absolute;
            top: 20px;
            left: 10px;
            width: 100px;
            height: 100px;
            cursor: move;
            background: green;
        }
    </style>
</head>
<body>
<div id="mark"></div>
<script charset="utf-8" type="text/javascript" src="jss/event.js"></script>
<script type="text/javascript">
    var mark = document.getElementById("mark");
    var winW = document.documentElement.clientWidth || document.body.clientWidth, winH = document.documentElement.clientHeight || document.body.clientHeight;
    var markW = mark.offsetWidth, markH = mark.offsetHeight;
    on(mark, "mousedown", dragDown);

    function dragDown(e) {
        this["strX"] = e.clientX;//this["strX"]存的自定义属性
        this["strY"] = e.clientY;
        this["strL"] = this.offsetLeft;
        this["strT"] = this.offsetTop;
        if (this.setCapture) {//->IE和火狐
            this.setCapture();
            zhufengEvent.on(this, "mousemove", dragMove);
            zhufengEvent.on(this, "mouseup", dragUp);
        } else {
            var _this = this;
            this.MOVE = function (e) {
                dragMove.call(_this, e);
            };
            this.UP = function (e) {
                dragUp.call(_this, e);
            };
            on(document, "mousemove", this.MOVE);
            on(document, "mouseup", this.UP);

            //->清除正在运行的动画
            window.clearInterval(this.flyTimer);
            window.clearInterval(this.dropTimer);
        }
    }
    function dragMove(e) {
        var curL = e.clientX - this["strX"] + this["strL"];
        var curT = e.clientY - this["strY"] + this["strT"];
        var minL = 0, minT = 0, maxL = winW - markW, maxT = winH - markH;
        curL = curL <= minL ? minL : (curL >= maxL ? maxL : curL);
        curT = curT <= minT ? minT : (curT >= maxT ? maxT : curT);
        mark.style.left = curL + "px";
        mark.style.top = curT + "px";

        //->动画
        //浏览器中每一个事件行为都有一个最短的反应时间minTime,在minTime以内,不会重复触发这个行为,只有超过了这个最短时间才会触发下一次的行为
        //我们水平方向运动的速度取决于拖拽结束的那一瞬间,鼠标移动的距离;
        //console.log("ok");
        if (!this["flyPre"]) {
            this["flyPre"] = this.offsetLeft;
        } else {
            this["flySpeed"] = this.offsetLeft - this["flyPre"];
            this["flyPre"] = this.offsetLeft;
        }

    }
    function dragUp(e) {
        if (this.releaseCapture) {
            this.releaseCapture();
            off(this, "mousemove", dragMove);
            off(this, "mouseup", dragUp);
        } else {
            off(document, "mousemove", this.MOVE);
            off(document, "mouseup", this.UP);
        }
        //->拖拽结束执行动画
        fly.call(this);//让this变为当前元素
        drop.call(this);
    }

    //->水平方向的动画
    function fly() {
        //->this->mark
        var _this = this, speed = this["flySpeed"];
        _this.flyTimer = window.setInterval(function () {
            //->由于我们的offsetLeft每一次获取的值都会出现四舍五入,这样如果本次增加一个小于0.5的速度值的话,下一次获取的值还是上次的值,加的速度起不到作用,我们结束动画即可
            if (Math.abs(speed) < 0.5) {//可能是负值
                window.clearInterval(_this.flyTimer);
                return;
            }
            //console.log("ok");//动画结束了,定时器还没有结束
            speed *= 0.98;//每一次都让速度乘以一个小于1的值,这样我们的速度就在衰减
            var curL = _this.offsetLeft + speed;// _this.offsetLeft获取的是整数(四舍五入了)??????
            var minL = 0, minT = 0, maxL = winW - markW, maxT = winH - markH;
            if (curL >= maxL) {//到达右边界
                curL = maxL;
                speed *= -1;
            } else if (curL <= minL) {//到达左边界
                curL = minL;
                speed *= -1;
            }
            //console.log(curL);
            _this.style.left = curL + "px";
        }, 10);
    }

    //->垂直方向
    function drop() {
        var _this = this, speed = 9.8;
        _this["dropFlag"] = 0;
        _this.dropTimer = window.setInterval(function () {
            if (_this["dropFlag"] > 1) {
                window.clearInterval(_this.dropTimer);
                return;
            }
            speed += 10;
            speed *= 0.98;
            var curT = _this.offsetTop + speed;
            if (curT >= winH - markH) {//到底了
                curT = winH - markH;
                //return;
                speed *= -1;
                _this["dropFlag"]++;
            } else {//不在底
                _this["dropFlag"] = 0;
            }
            _this.style.top = curT + "px";

        }, 10);
    }
</script>
</body>
</html>

以上代码是页面HTML和实现动画的JS,下面是里面引用的jss里面的event.js文件:

//->基于内置类的原型扩展一个等价于bind的方法,预先把某一个函数中的this进行处理,把一些参数值预先传递进来(事件对象也可以获取到)
Function.prototype.myBind = function myBind(context) {
    //this->我要操作的那个函数
    var _this = this;
    var outerArg = Array.prototype.slice.call(arguments, 1);
    return function () {
        var innerArg = Array.prototype.slice.call(arguments, 0);
        _this.apply(context, outerArg.concat(innerArg));
    }
};
    //->清除正在运行的动画
    function bind(curEle, type, fn) {
        if (curEle.addEventListener) {
            curEle.addEventListener(type, fn, false);
            return;
        }
        var tempFn = fn.myBind(curEle);
        tempFn.photo = fn;

        !curEle["myBind" + type] ? curEle["myBind" + type] = [] : null;
        var ary = curEle["myBind" + type];
        for (var i = 0; i < ary.length; i++) {
            if (ary[i].photo === fn) {
                return;
            }
        }
        ary.push(tempFn);
        //curEle["myBind" + type].push(tempFn);
        curEle.attachEvent("on" + type, tempFn);
        //curEle.attachEvent("on"+type,fn.myBind(curEle));
    }


    function unbind(curEle, type, fn) {
        if (curEle.removeEventListener) {
            curEle.removeEventListener(type, fn, false);
            return;
        }
        var ary = curEle["myBind" + type];
        if (ary) {
            for (var i = 0; i < ary.length; i++) {
                var tempFn = ary[i];
                if (tempFn.photo === fn) {
                    curEle.detachEvent("on" + type, tempFn);
                    ary.splice(i, 1);
                    break;
                    //curEle.detachEvent("on" + type, fn.myBind(curEle));
                }
            }
        }
    }





//->自己模拟内置的事件池创建一个临时的容器,把所有需要绑定的方法先放在自己的容器中,然后值给元素的某个行为绑定一个方法run,(把这个方法需要增加到内置的事件池中)当行为触发的时候执行run方法,在run执行的过程中,我们在把通过on绑定的方法依次的按顺序执行即可;
function on(curEle, type, fn) {
    !curEle["myEvent" + type] ? curEle["myEvent" + type] = [] : null;
    var ary = curEle["myEvent" + type];
    for (var i = 0; i < ary.length; i++) {
        if (ary[i] === fn) {
            return;//重复了就不追加了,直接return
        }
    }
    ary.push(fn);
    bind(curEle, type, run);
}

function off(curEle, type, fn) {
    var ary = curEle["myEvent" + type];
    if (ary) {
        for (var i = 0; i < ary.length; i++) {
            var curFn = ary[i];
            if (curFn === fn) {
                ary[i] = null;
                break;
            }
        }
    }
}

function run(e) {
    if (window.event) {
        e.target = e.srcElement;
        e.pageX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
        e.pageY = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
        e.preventDefault = function () {
            e.returnValue = false;
        };
        e.stopPropagation = function () {
            e.cancelBubble = true;
        };
    }
    var ary = this["myEvent" + e.type];
    if (ary) {
        for (var i = 0; i < ary.length; i++) {
            var curFn = ary[i];
            if (typeof curFn === "function") {
                curFn.call(this, e);
                continue;
            }
            ary.splice(i, 1);
            i--;
        }
    }
}

通过以上的详细代码,就实现了我们的弹性势能动画

原文地址:https://www.cnblogs.com/kpengfang/p/5446547.html