JS实现动画方向切换效果(包括:撞墙反弹,暂停继续左右运动等)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>动画方向切换</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        a {
            text-decoration: none;
            color: #000000;
        }

        #demo {
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            top: 30px;
            left: 600px;
            border-radius: 50%;
        }

        .btn {
            width: 400px;
            margin: 150px auto;
        }

        .btn a {
            display: inline-block;
            width: 100px;
            line-height: 50px;
            background-color: greenyellow;
            margin: 0 10px;
            text-align: center;
            border: 2px solid darkgoldenrod;
        }
    </style>
</head>
<body>
<div id="demo"></div>
<div class="btn">
    <a href="javascript:;" id="btnLeft">向左</a>
    <a href="javascript:;" id="btnStart">开始/暂停</a>
    <a href="javascript:;" id="btnRight">向右</a>
</div>
<script src="utils.js"></script>
<script type="text/javascript">
    var oDiv = document.getElementById('demo'), btnLeft = document.getElementById('btnLeft'), btnRight = document.getElementById('btnRight'), btnStart = document.getElementById('btnStart');
    var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - oDiv.offsetWidth, initPos = utils.css(oDiv, 'left');
    btnStart.flag = 1;
    btnStart.onclick = function () {
        var target = null;
        this.flag === 1 ? target = maxLeft : target = 0;
        if (oDiv.run) {
            clearInterval(oDiv.timer);
            oDiv.run = false;
            return;
        }
        move(target);
    };
    btnLeft.onclick = function () {
        btnStart.flag === 1 ? btnStart.flag *= -1 : null;
        move(0);
    };
    btnRight.onclick = function () {
        btnStart.flag == -1 ? btnStart.flag *= -1 : null;
        move(maxLeft);
    };
    function move(target) {
        oDiv.run = true;
        _move();
        function _move() {
            clearInterval(oDiv.timer);
            var curPos = null;
            if (target) {
                curPos = utils.css(oDiv, 'left');
                curPos += 5;
                if (curPos >= target) {
                    utils.css(oDiv, 'left', maxLeft);
//                    clearInterval(oDiv.timer);
//                    oDiv.run = false;
//                    btnStart.flag *= -1;
                    target = 0;
                    btnStart.flag *= -1;
                    oDiv.timer = setTimeout(_move, 10);
                    return;
                }
                utils.css(oDiv, 'left', curPos);
            } else {
                curPos = utils.css(oDiv, 'left');
                curPos -= 5;
                if (curPos <= target) {
                    utils.css(oDiv, 'left', 0);
//                    clearInterval(oDiv.timer);
//                    oDiv.run = false;
//                    btnStart.flag *= -1;
                    target = maxLeft;
                    btnStart.flag *= -1;
                    oDiv.timer = setTimeout(_move, 10);
                    return;
                }
                utils.css(oDiv, 'left', curPos);
            }
            oDiv.timer = setTimeout(_move, 10);
        }
    }
</script>
</body>
</html>

附:utils.js代码文件

'use strict';
var utils = (function () {
    var isSupport = 'getComputedStyle' in window;

    /*
     * toArray:Converts an array of classes to an array
     * @parameter:
     *   likeAry[object]:Class array to convert
     * @return:
     *   ary[Array]:Convert completed array
     * By Team on 2017-04-16 12:44
     */
    function toArray(likeAry) {
        var ary = [];
        try {
            ary = Array.prototype.slice.call(likeAry);
        } catch (e) {
            for (var i = 0, len = likeAry.length; i < len; i++) {
                ary[ary.length] = likeAry[i];
            }
        }
        return ary;
    }

    /*
     * toJSON:Convert JSON string to JSON object
     * @parameter:
     *   str[String]:JSON string
     * @return:
     *   obj[Object]:JSON object
     * By Team on 2017-04-16 12:48
     */
    function toJSON(str) {
        return 'JSON' in window ? JSON.parse(str) : eval('(' + str + ')');
    }

    /*
     * win:Operating browser box model information
     */
    function win(attr, value) {
        if (typeof value === "undefined") {
            return document.documentElement[attr] || document.body[attr];
        }
        document.documentElement[attr] = value;
        document.body[attr] = value;
    }

    /*
     * getCss:Gets the value of the specific style property for the current element
     * @parameter:
     *   curEle[object]:current element
     *   attr[string]:style properties of elements
     * @return:
     *   Style attribute values for elements
     * By Team on 2017-04-23 12:29
     */
    function getCss(curEle, attr) {
        var val = null,
            reg = null;
        if (isSupport) {
            val = window.getComputedStyle(curEle, null)[attr];
        } else {
            //->IE6~8
            switch (attr) {
                case 'filter':
                case 'opacity':
                    val = curEle.currentStyle['filter'];
                    reg = /alpha(opacity=(.+))/i;
                    val = reg.test(val) ? RegExp.$1 / 100 : 1;
                    break;
                default:
                    val = curEle.currentStyle[attr];
            }
        }
        reg = /^-?d+(.d+)?(px|rem|em|pt)?$/i;
        val = reg.test(val) ? parseFloat(val) : val;
        return val;
    }

    /*
     * getCss:Set the style property value for an element,Setting inline styles for elements
     * @parameter:
     *   curEle[object]:current element
     *   attr[string]:style properties of elements
     *   value:set style property value
     * By Team on 2017-04-23 15:36
     */
    function setCss(curEle, attr, value) {
        if (attr === 'float') {
            curEle['style']['cssFloat'] = value;
            curEle['style']['styleFloat'] = value;
            return;
        }
        if (attr === 'opacity') {
            curEle['style']['opacity'] = value;
            curEle['style']['filter'] = 'alpha(opacity=' + value * 100 + ')';
            return;
        }
        var reg = /^(?:width|height|(?:(?:margin|padding)?(?:top|left|right|bottom)))$/i;
        if (reg.test(attr)) {
            !isNaN(value) ? value += 'px' : null;
        }
        curEle['style'][attr] = value;
    }

    /*
     * setGroupCss:Set the style attribute value for the batch
     * @parameter:
     *   curEle[object]:current element
     *   styleCollection[object]:style collection
     * By Team on 2017-04-23 15:36
     */
    function setGroupCss(curEle, styleCollection) {
        for (var key in styleCollection) {
            if (styleCollection.hasOwnProperty(key)) {
                setCss(curEle, key, styleCollection[key]);
            }
        }
    }

    /*
     * css:The style properties of the operating element, including the capture style, the individual settings style, and the batch settings style
     * @parameter:
     *   curEle[object]:current element
     * By Team on 2017-04-23 15:36
     */
    function css() {
        var arg = arguments;
        if (arg.length >= 3) {
            //->SET CSS
            setCss.apply(this, arg);
            return;
        }
        if (arg.length === 2 && typeof arg[1] === 'object') {
            //->SET GROUP CSS
            setGroupCss.apply(this, arg);
            return;
        }
        return getCss.apply(this, arg);
    }

    /*
     * offset:Gets the offset of the current element distance BODY
     * @parameter:
     *   curEle[object]:current element
     * @return:
     *   [object]:{top:xxx,left:xxx}
     * By Team on 2017-04-23 16:43
     */
    function offset(curEle) {
        var l = curEle.offsetLeft,
            t = curEle.offsetTop,
            p = curEle.offsetParent;
        while (p) {
            if (navigator.userAgent.indexOf('MSIE 8') === -1) {
                l += p.clientLeft;
                t += p.clientTop;
            }
            l += p.offsetLeft;
            t += p.offsetTop;
            p = p.offsetParent;
        }
        return {top: t, left: l};
    }

    /*
     * hasClass:Verify that the current element contains a single style class name
     * @parameter:
     *   curEle[object]:current element
     *   cName[string]:class name to validate
     * @return:
     *   [boolean]:true/false
     * By Team on 2017-04-29 11:16
     */
    function hasClass(curEle, cName) {
        return new RegExp('(^| +)' + cName + '( +|$)').test(curEle.className);
    }

    /*
     * hasClass:Adds a class name to the current element
     * @parameter:
     *   curEle[object]:current element
     *   strClass[string]:Need to increase the style class name, can be more than, for example:'xxx','xxx xxx', '  xxx    xxx  '...
     * By Team on 2017-04-29 11:28
     */
    function addClass(curEle, strClass) {
        strClass = strClass.replace(/(^ +| +$)/g, '').split(/ +/g);
        for (var i = 0; i < strClass.length; i++) {
            var curClass = strClass[i];
            if (!hasClass(curEle, curClass)) {
                curEle.className += ' ' + curClass;
            }
        }
    }

    /*
     * removeClass:Remove a class name to the current element
     * @parameter:
     *   curEle[object]:current element
     *   strClass[string]:Need to deleted the style class name, can be more than, for example:'xxx','xxx xxx', '  xxx    xxx  '...
     * By Team on 2017-04-29 11:44
     */
    function removeClass(curEle, strClass) {
        strClass = strClass.replace(/(^ +| +$)/g, '').split(/ +/g);
        for (var i = 0; i < strClass.length; i++) {
            var curClass = strClass[i],
                reg = new RegExp('(^| )' + curClass + '( |$)', 'g');
            hasClass(curEle, curClass) ? curEle.className = curEle.className.replace(/ /g, '  ').replace(reg, ' ') : null;
        }
        curEle.className = curEle.className.replace(/(^ +| +$)/g, '');
    }

    /*
     * toggleClass:If the passing style class name exists in the element, the delete operation is an operation
     * @parameter:
     *   curEle[object]:current element
     *   strClass[string]:class name to be operated
     * By Team on 2017-04-29 12:00
     */
    function toggleClass(curEle, strClass) {
        strClass = strClass.replace(/(^ +| +$)/g, '').split(/ +/g);
        for (var i = 0; i < strClass.length; i++) {
            var curClass = strClass[i];
            hasClass(curEle, curClass) ? removeClass(curEle, curClass) : addClass(curEle, curClass);
        }
    }

    /*
     * byClass:Gets a set of elements by the element's style class,Compatible IE low version browser
     * @parameter:
     *   strClass[string]:class name to be operated
     *   context[HTMLElementObject]:get the range, the default is document
     * @return:
     *   [Array]:All matching results
     * By Team on 2017-04-29 12:56
     */
    function byClass(strClass, context) {
        context = context || document;
        if (isSupport) {
            return toArray(context.getElementsByClassName(strClass));
        }
        //->IE6~8
        var allList = context.getElementsByTagName('*'),
            ary = [],
            reg = null;
        strClass = strClass.replace(/(^ +| +$)/g, '')
            .replace(/ +/g, '@@')
            .replace(/(?:^|@)([w-]+)(?:@|$)/g, '(?=.*(^| +)$1( +|$).*)');
        reg = new RegExp(strClass);
        for (i = 0; i < allList.length; i++) {
            var cur = allList[i];
            reg.test(cur.className) ? ary[ary.length] = cur : null;
        }
        return ary;
    }

    /*
     * children:Gets all the child nodes of the current container (element), which is filtered in all child elements, and specifies the name of the tag
     * @parameter
     *    curEle[HTMLElement]:current element
     *    tagName[string]:tag name
     * @return
     *    [array]:Collection of elements
     */
    function children(curEle, tagName) {
        var allNodes = curEle.childNodes,
            elementAry = [];
        for (var i = 0; i < allNodes.length; i++) {
            var curNode = allNodes[i];
            if (curNode.nodeType === 1) {
                var curNodeTag = curNode.tagName.toUpperCase();
                if (typeof tagName !== 'undefined') {
                    tagName = tagName.toUpperCase();
                    curNodeTag === tagName ? elementAry[elementAry.length] = curNode : null;
                    continue;
                }
                elementAry[elementAry.length] = curNode;
            }
        }
        return elementAry;
    }

    /*
     * prev:Get older brother element node
     */
    function prev(curEle) {
        if (isSupport) {
            return curEle.previousElementSibling;
        }
        var p = curEle.previousSibling;
        while (p && p.nodeType !== 1) {
            p = p.previousSibling;
        }
        return p;
    }

    /*
     * prevAll:Get all brother element node
     */
    function prevAll(curEle) {
        var ary = [],
            p = prev(curEle);
        while (p) {
            ary.unshift(p);
            p = prev(p);
        }
        return ary;
    }

    /*
     * next:Get next brother element node
     */
    function next(curEle) {
        if (isSupport) {
            return curEle.nextElementSibling;
        }
        var n = curEle.nextSibling;
        while (n && n.nodeType !== 1) {
            n = n.nextSibling;
        }
        return n;
    }

    /*
     * nextAll:Get all brother element node
     */
    function nextAll(curEle) {
        var ary = [],
            n = next(curEle);
        while (n) {
            ary.push(n);
            n = next(n);
        }
        return ary;
    }

    /*
     * siblings:Get all sibling element nodes
     */
    function siblings(curEle) {
        return prevAll(curEle).concat(nextAll(curEle));
    }

    /*
     * index:Gets the index of the current element
     */
    function index(curEle) {
        return prevAll(curEle).length;
    }

    /*
     * firstChild:Gets the first child element in the container
     */
    function firstChild(curEle) {
        if (isSupport) {
            return curEle.firstElementChild;
        }
        var first = curEle.firstChild;
        while (first && first.nodeType !== 1) {
            first = first.nextSibling;
        }
        return first;
    }

    /*
     * lastChild:Gets the last child element in the container
     */
    function lastChild(curEle) {
        if (isSupport) {
            return curEle.lastElementChild;
        }
        var last = curEle.lastChild;
        while (last && last.nodeType !== 1) {
            last = last.previousSibling;
        }
        return last;
    }

    /*
     * prepend:Add a new element to the location of the specified container
     * @parameter
     *   newEle:Newly added elements
     *   container:Specified container
     */
    function prepend(newEle, container) {
        var first = firstChild(container);
        if (first) {
            container.insertBefore(newEle, first);
            return;
        }
        container.appendChild(newEle);
    }

    /*
     * insertAfter:Add a new element to the old element
     * @parameter
     *   newEle:New elements
     *   oldEle:Original element
     */
    function insertAfter(newEle, oldEle) {
        var n = next(oldEle),
            p = oldEle.parentNode;
        if (n) {
            p.insertBefore(newEle, n);
            return;
        }
        p.appendChild(newEle);
    }

    return {
        /*--TOOL--*/
        toArray: toArray,
        toJSON: toJSON,
        win: win,

        /*--CSS OR STYLE--*/
        offset: offset,
        css: css,
        hasClass: hasClass,
        addClass: addClass,
        removeClass: removeClass,
        toggleClass: toggleClass,

        /*--GET ELEMENTS--*/
        byClass: byClass,
        children: children,
        prev: prev,
        next: next,
        prevAll: prevAll,
        nextAll: nextAll,
        siblings: siblings,
        index: index,
        firstChild: firstChild,
        lastChild: lastChild,

        /*--OPERATING ELEMENT--*/
        insertAfter: insertAfter,
        prepend: prepend
    }
})();
原文地址:https://www.cnblogs.com/Scar007/p/7724629.html