正确清除多个超时

Clearing multiple timeouts properly

过去一天我一直在努力解决这个问题。

我正在尝试使用一些时髦的文字效果,基本上是一个美化的字符串创建。 它写一行有点像广告牌,为此我使用了 setTimeout。 事情是我想把它放在一个函数中,这样我就可以重用它并在不同的元素上多次调用它。

问题是我可能需要在中途将文本更新为新文本。 为此,我清除了超时,但除非计时器变量超出范围,否则它不会清除。

因为实用性,我实在不能把它放在功能之外; 我不确定它会被调用多少次,感觉在函数外声明 20 个时间变量是不对的。

这是在一项上正确工作的代码 (多次点击中断重启)

    var t;
    function writeStats(str,dest) {

        var options = {
                "step"  : 8,    // How many times should the letters be changed
                "fps"   : 25,   // Frames Per Second
                "text"  : ""    // Use this text instead of the contents
            }
        
        function randomChar(type){
            var pool = "";

            if (type == "lowerLetter"){
                pool = "abcdefghijklmnopqrstuvwxyz0123456789";
            }
            else if (type == "upperLetter"){
                pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            }
            else if (type == "symbol"){
                pool = ",.?/\(^)![]{}*&^%$#'\"";
            }

            var arr = pool.split('');
            return arr[Math.floor(Math.random()*arr.length)];
        }

        str = str.split('');

        var types = [],
            letters = [];

        for(var i=0;i<str.length;i++){

            var ch = str[i];

            if(ch == " "){
                types[i] = "space";
                continue;
            }
            else if(/[a-z]/.test(ch)){
                types[i] = "lowerLetter";
            }
            else if(/[A-Z]/.test(ch)){
                types[i] = "upperLetter";
            }
            else {
                types[i] = "symbol";
            }

            letters.push(i);
        }

        clearTimeout(t);

        (function shuffle(start){

            // This code is run options.fps times per second
            // and updates the contents of the page element

            var i,
                len = letters.length,
                strCopy = str.slice(0); // Fresh copy of the string

            if(start>len){
                return;
            }

            // All the work gets done here
            for(i=Math.max(start,0); i < len; i++){

                // The start argument and options.step limit
                // the characters we will be working on at once

                if( i < start+options.step){
                    // Generate a random character at this position
                    strCopy[letters[i]] = randomChar(types[letters[i]]);
                }
                else {
                    strCopy[letters[i]] = "";
                }
            }

            //el.text(strCopy.join(""));
            el = strCopy.join("");
            //console.log(el);
            $('.'+dest).text(el);

            t = setTimeout(function(){

                shuffle(start+1);

            },500/options.fps);

        })(-options.step);

    }

    $(document).ready(function(){
        $(document).click(function(){
            writeStats('this sentence is a great one','t1');
        });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<div class="t1"></div>
<div class="t2"></div>
和一个 Fiddle 脚本:https://jsfiddle.net/phjzfw15/

如果我像这样将 t 变量带入函数内部,它就不会像以前那样工作了:

function writeStats(str,dest) {
        var t;
        var options = {
                "step"  : 8,    // How many times should the letters be changed
                "fps"   : 25,   // Frames Per Second
                "text"  : ""    // Use this text instead of the contents
            }
        
        function randomChar(type){
            var pool = "";

            if (type == "lowerLetter"){
                pool = "abcdefghijklmnopqrstuvwxyz0123456789";
            }
            else if (type == "upperLetter"){
                pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            }
            else if (type == "symbol"){
                pool = ",.?/\(^)![]{}*&^%$#'\"";
            }

            var arr = pool.split('');
            return arr[Math.floor(Math.random()*arr.length)];
        }

        str = str.split('');

        var types = [],
            letters = [];

        for(var i=0;i<str.length;i++){

            var ch = str[i];

            if(ch == " "){
                types[i] = "space";
                continue;
            }
            else if(/[a-z]/.test(ch)){
                types[i] = "lowerLetter";
            }
            else if(/[A-Z]/.test(ch)){
                types[i] = "upperLetter";
            }
            else {
                types[i] = "symbol";
            }

            letters.push(i);
        }

        clearTimeout(t);

        (function shuffle(start){

            // This code is run options.fps times per second
            // and updates the contents of the page element

            var i,
                len = letters.length,
                strCopy = str.slice(0); // Fresh copy of the string

            if(start>len){
                return;
            }

            // All the work gets done here
            for(i=Math.max(start,0); i < len; i++){

                // The start argument and options.step limit
                // the characters we will be working on at once

                if( i < start+options.step){
                    // Generate a random character at this position
                    strCopy[letters[i]] = randomChar(types[letters[i]]);
                }
                else {
                    strCopy[letters[i]] = "";
                }
            }

            //el.text(strCopy.join(""));
            el = strCopy.join("");
            //console.log(el);
            $('.'+dest).text(el);

            t = setTimeout(function(){

                shuffle(start+1);

            },500/options.fps);

        })(-options.step);

    }

    $(document).ready(function(){
        $(document).click(function(){
            writeStats('this sentence is a great one','t1');
        });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<div class="t1"></div>
    <div class="t2"></div>
...和亲戚 fiddle 如果你喜欢的话:https://jsfiddle.net/phjzfw15/1/

如果您 运行 代码段,您会发现它不再正常工作。 反复点击会显示旧句子仍然存在并且被覆盖了。 我怎样才能在函数内部正确清除超时?

我认为 "t" 变量是每个函数的局部变量,并且会创建一个单独的实例?

谢谢!

ok,给个精简版(可能之前代码量太大了) 正确版本

    var starr = [
        'bloop the boop',
        'cammy the shadow',
        'i like cauliflower',
        'bro, i kick u hard',
        'like measels? I dont.',
        'eat fish and pie'
    ];

    var timer;

    function writeStats(str, dest) {
        
        $('.'+dest).text('');

        var options = {
                "step"  : 8,    // How many times should the letters be changed
                "fps"   : 25,   // Frames Per Second
                "text"  : ""    // Use this text instead of the contents
            }
        
        str = str.split('');
        
        clearTimeout(timer);
        var ll = '';
        (function shuffle(start){
            // This code is run options.fps times per second
            // and updates the contents of the page element

            var i, len = str.length, el;
            

            if(start>=len){
                return;
            }          
            ll = ll + str[start];
            $('.'+dest).text(ll);

            timer = setTimeout(function(){

                shuffle(start+1);

            },1500/options.fps);
        })(0);

    }

    $(document).ready(function(){
        var index = 0;
        $(document).click(function(){
            writeStats(starr[index],'t1');
            if (index == 5) index = 0; else index++;
        });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
Correct version
<div class="t1">Click anywhere multiple times</div>

无效版本

    var starr = [
        'bloop the boop',
        'cammy the shadow',
        'i like cauliflower',
        'bro, i kick u hard',
        'like measels? I dont.',
        'eat fish and pie'
    ];



    function writeStats(str, dest) {
        var timer;
        $('.'+dest).text('');

        var options = {
                "step"  : 8,    // How many times should the letters be changed
                "fps"   : 25,   // Frames Per Second
                "text"  : ""    // Use this text instead of the contents
            }
        
        str = str.split('');
        
        clearTimeout(timer);
        var ll = '';
        (function shuffle(start){
            // This code is run options.fps times per second
            // and updates the contents of the page element

            var i, len = str.length, el;
            

            if(start>=len){
                return;
            }          
            ll = ll + str[start];
            $('.'+dest).text(ll);

            timer = setTimeout(function(){

                shuffle(start+1);

            },1500/options.fps);
        })(0);

    }

    $(document).ready(function(){
        var index = 0;
        $(document).click(function(){
            writeStats(starr[index],'t1');
            if (index == 5) index = 0; else index++;
        });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
NOT WORKING VERSION (please note I just moved the timer declaration inside the function)
<div class="t1">Click anywhere multiple times fast</div>

终于成功了。 为后人...

    var starr = [
        'bloop the boop',
        'cammy the shadow',
        'i like cauliflower',
        'bro, i kick u hard',
        'like measels? I dont.',
        'eat fish and pie'
    ];

        var writer = function(){
            
            var timer;

            this.writeStat = function(str,dest) {

                var options = { "step"  : 8, "fps"   : 25, "text"  : "" }
                
                str = str.split('');
                
                clearTimeout(timer);
                var ll = '';
                
                (function shuffle(start){
                    // This code is run options.fps times per second
                    // and updates the contents of the page element
        
                    var i, len = str.length, el;
                    
        
                    if(start>=len){
                        return;
                    }          
                    ll = ll + str[start];
                    $('.'+dest).text(ll);
        
                    timer = setTimeout(function(){
        
                        shuffle(start+1);
        
                    },1500/options.fps);
                })(0);
            }
        }

    $(document).ready(function(){
        var index = 0;
        w = new writer;
        y = new writer;
        $(document).click(function(){
            
            w.writeStat(starr[index],'t1');
            y.writeStat(starr[index],'t2');
            if (index == 5) index = 0; else index++;
        });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div class="t1"></div>
<div class="t2"></div>