不在焦点时在文本框中反复写字,在焦点时停止

Iteratively write words in a textbox when not in focus and stop when in focus

我有一个简单的任务是根据它是否处于焦点状态来与普通文本框进行交互,但我对如何使用 jQuery.[=20= 开始和停止迭代过程感到困惑]

目标

我有一个 HTML 文本框,其中包含 data-* 属性中几个 space 分隔的单词的数据:<input type="text" data-queries="The big brown fox jumped" ...>

每当文本框不在焦点上(以及页面加载时),我希望文本框的值每秒更改一次,连续迭代 data-queries 属性中的不同单词。

一旦文本框处于焦点状态,我希望迭代停止并将值设为空白(以便显示占位符文本)。

到目前为止我的代码

HTML

<form class="form-horizontal" action="" autocomplete="on">
    <label for="search"><h3 class="text-default">My Label</h3></label> 
    <input class="landing-search ml-15" data-queries="The big brown fox jumped" id="search" name="search" type="text" placeholder="Search...">
</form>

JS

//Function that writes each string in @words one second apart
//then calls itself recursively to repeat
//Tries to "stop" by checking if selector is in focus
//but stops only after last word is reached, not immediately when in focus
    function write_to_textbox_loop(selector, words) {
            if(selector.is(":focus")) {
                return;
            }
            for(var i = 0; i < words.length; i++){
                (function(i){
                    setTimeout(function(){
                        selector.val(words[i]);
                    }, 1000*i); 
                })(i);
            }

            setTimeout(function(){
                write_to_textbox_loop(selector, words);
            }, 1000*(words.length));
    }

    if($('.landing-search').length > 0) {

            data_queries = $('.landing-search').attr('data-queries').split(' ')

            //Write data-query attribute values into search textbox when not in focus
            $('.landing-search').focusout(function(){
                write_to_textbox_loop($(this), data_queries);
            });

            $('.landing-search').focus(function(){
                $(this).val('');
    });

正如我在评论中所写,这实现了所需的迭代效果(尽管我不确定为什么只使用 1000*words.length 的递归调用在没有任何其他增量的情况下永远有效,因为所有 setTimeout调用几乎立即发生,但它确实有效:当我移除焦点时,它会永远循环播放所有单词。

但是,当我单击文本框并将其置于焦点时,它只会在写完该循环中的最后一个单词后才会停止。这是有道理的,因为我在一系列递归调用中以 return 停止,但我需要它立即停止 .

如何让我永远循环的文字在文本框进入焦点时立即停止,然后在失去焦点时重新开始?

编辑: 我想过使用 clearTimeout() 但它需要你想要停止的 setTimeout 变量我无法弄清楚如何跟踪我递归创建的所有不同 setTimeout() 调用的逻辑。

谢谢!

你可以写一个小插件,让它更容易复用

$.fn.inputShow = function(opts) {
    var start = true;
    
    return this.each(function() {
     if ( opts === false ) {
            clearInterval( $(this).data('timer') );
            this.value = '';
        } else {
            var words = $(this).data('queries').split(/\b/).filter(function(x) { return x.trim().length });
            var i = $(this).data('i') || 0;
            
            if (start) this.value = words[i];
            
            $(this).data('timer', setInterval(function() {
                start = false;
                this.value = words[i+1] ? words[++i] : words[i=0];
                $(this).data('i', i);
            }.bind(this), opts || 1000));
        }
    });
}

$('.landing-search').on({
 focus : function() {
     $(this).inputShow(false); // stops it
    },
    blur: function() {
     $(this).inputShow(1000); // starts it, delay of 1000 milliseconds
    }
}).trigger('blur'); // start on pageload
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form class="form-horizontal" action="" autocomplete="on">
    <label for="search"><h3 class="text-default">My Label</h3></label> 
    <input class="landing-search ml-15" data-queries="The big brown fox jumped" id="search" name="search" type="text" placeholder="Search...">
</form>