setTimeout函数完全冻结任何输出?

时间:2016-09-29 05:16:39

标签: javascript jquery html css settimeout

我一直在尝试使用jQuery创建一个Nav,其中一部分是旋转齿轮PNG,我在这里看了一下,发现有人描述了如何在没有插件的情况下做到这一点,但我修改了他们的代码所以不是每次点击改变角度而是改变它,以便它从0到180改变角度,每个步骤之间有延迟,因此setTimeout函数。无论如何这里是代码。

HTML

<!DOCTYPE html>
  <html>

  <head>
    <meta charset="utf-8">
    <script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-         16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="   crossorigin="anonymous">   </script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" integrity="sha256-T0Vest3yCU7pafRw9r+settMBX6JkKN06dqBnpQ8d30="   crossorigin="anonymous"></script>
    <script src="main.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="mystyle.css">
  </head>

  <body>
    <div id="header">
     <div id="gear">
      <img src="gear.png">
     </div>
    </div>
  </body>

  </html>

CSS

#header {
    position: relative;
}

#gear {
    position: absolute;
    left: 50px;  
}

JS

$(document).ready(function() {

  var rotDeg = 0;
  var rotEnd = 180;

  jQuery.fn.rotate = function(degrees) {
      $(this).css({'-webkit-transform' : 'rotate('+ degrees +'deg)',
                   '-moz-transform' : 'rotate('+ degrees +'deg)',
                   '-ms-transform' : 'rotate('+ degrees +'deg)',
                   'transform' : 'rotate('+ degrees +'deg)'});
      return $(this);
  };
    $('#gear').click(function() {
      while(rotDeg <= rotEnd) {
       setTimeout(function() {
         rotDeg += 1;
         $(this).rotate(rotDeg);
       }, 34);
      }
    });
});

2 个答案:

答案 0 :(得分:0)

setTimeout计划函数在至少给定的毫秒数后运行,但仅在没有其他代码运行时运行。但是,你的while循环永远不会结束,因为rotDeg在循环中没有改变(因为永远不会调用回调),并且由于这会导致无限循环,所以从来没有任何其他代码没有其他代码正在运行,并且可以运行预定的回调。

解决方案是删除while循环,而是执行类似递归调用的函数:

$('#gear').click(function() {
  var that = this; // <-- this is important, since we cannot use `this`
                   // inside an inner function, like you did in your
                   // original code

  const func = function() {
    // note that the condition here is negated, compared to the while loop
    if(rotDeg > rotEnd)
      return;

    // do stuff
    rotDeg += 1; 
    $(that).rotate(rotDeg); // <-- again, note `that` that we defined above

    // do next "iteration" after at least 34 ms
    setTimeout(func, 34);
  };

  func();
});

另请注意,您不能在此处使用内部函数中的this; this answer中详细解释了原因。

答案 1 :(得分:0)

$(document).on('click', '#btn_highlight', function() {
    select('#highlight');
    apply('highlight');
});

$(document).on('click', '#btn_crossout', function() {
    select('#crossout');
    apply('crossout');
});

function select(id) {
    function append(id, begin, end) {
        // console.log('Add: ' + begin + ' to ' + end);
        var highlights = $(id).val().trim().split(',');
        var start = -1;
        var done = -1;
        var duplicate = -1;
        var inside = -1;
        var out = [];
        var previous = 99999999;
        var on = false;
        for (x in highlights) {
            var mark = highlights[x];
            if (!mark) continue;
            // console.log('Check: ' + mark + ' Start: ' + start + ' End: ' + done);
            if (duplicate == mark) {
                // console.log('Repeated mark');
                out.push(mark);
            }
            if (done >= 0) {
                out.push(mark);
                continue;
            } else if (start < 0) {
                if (end < mark) {
                    // console.log('Prepend new');
                    out.push(begin);
                    out.push(end);
                    out.push(mark);
                    start = mark;
                    done = end;
                } else if (end == mark || begin < mark) {
                    if (!on && end <= mark) {
                        // console.log('Prepend consecutive');
                        out.push(begin);
                        out.push(end);
                        out.push(mark);
                        done = mark;
                    } else if (on) {
                        // console.log('Start inside');
                        inside = begin
                    } else {
                        // console.log('Start new');
                        out.push(begin);
                    }
                    start = begin;
                } else if (begin == mark) {
                    // console.log('Start overlapped');
                    duplicate = mark;
                    start = mark;
                } else {
                    // console.log('Skip one');
                    out.push(mark);
                }
            }
            if (done < 0 && start >= 0) {
                if (end == mark) {
                    if (inside >= 0) {
                        // console.log('End overlapped from inside');
                        out.push(inside);
                        on = !on;
                    } else if (duplicate < 0) {
                        // console.log('End overlapped from outside');
                        out.push(end);
                    }
                    done = mark;
                } else if (end > previous && end < mark) {
                    if (!on || duplicate >= 0) {
                        // console.log('End new');
                        out.push(end);
                    }
                    out.push(mark);
                    done = mark;
                }
            }
            on = !on;
            // console.log(out);
            previous = mark;
        }
        if (done < 0) {
            if (duplicate >= 0 && begin == mark) {
                out.push(begin);
                out.push(begin);
                out.push(end);
            } else {
                if (start < 0) {
                    out.push(begin);
                } else if (duplicate >= 0) {
                    // console.log('End from duplicate');
                    out.push(duplicate);
                }
                out.push(end);
            }
        }
        $(id).val(out.toString().trim(','));
        // console.log(id + ': ' + $(id).val());
        if (out.length % 2 != 0) {
            console.log('Error!');
        }
    }
    var temp = '#temp';
    function getIndex(elem, offset) {
        var parent = $(elem).parents('.highlight_area');
        elem.nodeValue = temp + elem.nodeValue;
        var text = parent.text();
        var add = text.indexOf(temp);
        offset = offset + add;
        elem.nodeValue = elem.nodeValue.substr(temp.length);
        return offset;
    }
    function getIndex2(elem, offset) {
        var parent = elem.parents('.highlight_area');
        elem.text(temp + elem.text());
        var text = parent.text();
        var add = text.indexOf(temp);
        offset = offset + add;
        elem.text(elem.text().substr(temp.length));
        return offset;
    }
    function getElem(node) {
        if (node.is('.highlight,.crossout')) {
            node = node.parent();
        }
        return node;
    }
    var highlight = window.getSelection();
    // console.log(highlight);
    var base = highlight.focusNode;
    var anchor = highlight.anchorNode;
    var baseOffset = highlight.focusOffset;
    var anchorOffset = highlight.anchorOffset;
    if (!highlight.rangeCount || !$(base).parents('.highlight_area').length || !$(anchor).parents('.highlight_area').length) {
        // console.log(highlight.rangeCount + ' ; ' + $(base).parents('.highlight_area').length + ' ; ' + $(anchor).parents('.highlight_area').length);
        return;
    }
    baseOffset = getIndex(base, baseOffset);
    anchorOffset = getIndex(anchor, anchorOffset);
    var stem = $('.highlight_area');
    var baseIndex = getElem($(base.parentElement)).index();
    var anchorIndex = getElem($(anchor.parentElement)).index();
    var start = Math.min(baseOffset, anchorOffset);
    var end = Math.max(baseOffset, anchorOffset);
    // console.log('Offset: ' + start + ' to ' + end);
    // console.log('Indexes: ' + baseIndex + ' v ' + anchorIndex);
    if (baseIndex == anchorIndex) {
        append(id, start, end);
    } else {
        var children = stem.find(':not(.highlight,.crossout)');
        var startIndex = Math.min(baseIndex, anchorIndex);
        var endIndex = Math.max(baseIndex, anchorIndex);
        var child = $(children[startIndex]);
        var text = child.text();
        var textStart = getIndex2(child, text.length);
        append(id, start, textStart);
        for (var i = startIndex + 1; i < endIndex; i++) {
            child = $(children[i]);
            text = child.text();
            if (!text.trim().length) continue;
            append(id, textStart, textStart + text.length);
            textStart = textStart + text.length;
        }
        var child = $(children[endIndex]);
        var textStart = getIndex2(child, 0);
        append(id, textStart, end);
    }
}
function apply() {
    var highlights = $('#highlight').val().split(',');
    var crossouts = $('#crossout').val().split(',');
    var marks = {};
    for (x in highlights) {
        if (typeof marks[highlights[x]] != 'undefined') {
            // 2 consecutive highlights
            marks[highlights[x]] = 4;
        } else {
            marks[highlights[x]] = 1;
        }
    }
    for (x in crossouts) {
        if (typeof marks[crossouts[x]] == 'undefined') {
            marks[crossouts[x]] = 2;
        } else {
            if (marks[crossouts[x]] == 4) {
                // 2 highlights and a crossout
                marks[crossouts[x]] = 6;
            } else if (marks[crossouts[x]] == 2) {
                // 2 consecutive crossouts
                marks[crossouts[x]] = 5;
            } else if (marks[crossouts[x]] == 6) {
                // 2 consecutive highlights and crossouts
                marks[crossouts[x]] = 7;
            } else if (marks[crossouts[x]] == 3) {
                // 2 consecutive crossouts and highlight
                marks[crossouts[x]] = 8;
            } else {
                // highlight and crossout
                marks[crossouts[x]] = 3;
            }
        }
    }
    var stem = $('.highlight_area');
    var children = stem.find(':not(.highlight,.crossout)');
    var childIndex = 0;
    var child = $(children[childIndex]);
    var text = child.text().replace(/(<([^>]+)>)/ig, "");
    var high = false;
    var cross = false;
    var previousMark = 0;
    var passedChars = 0;
    var mode = 0;
    var string = '';
    var nextEdge = 0;
    stem.empty();
    child.empty();
    var first = true;
    var maxLoop = 10;
    for (x in marks) {
        if (x == '') continue;
        // console.log('Mark: ' + x);
        nextEdge = 1 * passedChars + 1 * text.length;
        // console.log('Next edge: ' + nextEdge);
        var loopCount = 0;
        while (x > nextEdge && loopCount++ < maxLoop) {
            string = text.substr(previousMark - passedChars);
            stem.append(child.append(string));
            passedChars = 1 * passedChars + 1 * text.length;
            previousMark = passedChars;
            // move on to next
            childIndex = childIndex + 1;
            child = $(children[childIndex]);
            text = child.text();
            child.empty();
            nextEdge = 1 * text.length + 1 * passedChars;
            // console.log('Next edge : ' + nextEdge);
        }
        // console.log('Select: ' + previousMark + ' to ' + x);
        string = text.substr(previousMark - passedChars, x - previousMark);
        // console.log(string);
        var type = '';
        if (high) {
            type = type + ' highlight';
        }
        if (cross) {
            type = type + ' crossout';
        }
        if (type) {
            var span = $('<span></span>').addClass(type);
            span.text(string);
            child.append(span);
        } else {
            child.append(string);
        }
        previousMark = x;
        if (marks[x] == 1) {
            high = !high;
        } else if (marks[x] == 2) {
            cross = !cross;
        } else if (marks[x] == 3) {
            high = !high;
            cross = !cross;
        } else if (marks[x] == 4) {
            high = true;
        } else if (marks[x] == 5) {
            cross = true;
        } else if (marks[x] == 6) {
            high = true;
            cross = !cross;
        } else if (marks[x] == 7) {
            high = true;
            cross = true;
        } else if (marks[x] == 8) {
            high = !high;
            cross = true;
        }
    }
    string = text.substr(previousMark - passedChars);
    stem.append(child.append(string));
    childIndex = childIndex + 1;
    while (childIndex < children.length) {
        child = $(children[childIndex]);
        child.find('.highlight,.crossout').each(function(i, e) {
            child.html(child.html().replace($(e).outerHtml(), $(e).text()));
        });
        stem.append(child);
        childIndex = childIndex + 1;
    }
}
apply();

这启动了自动调用函数mov,它每100毫秒调用一次...