1
function say(str){
    for(i=0;i<str.length;i++){
        setTimeout(function(){
            $("#text").append(str[i]);
            console.log(str[i]);
        },
        i*200);
    }
}

say("Hello World !");

看:http: //jsfiddle.net/XnKNX/

似乎每个str[i]都是未定义的;

如何让它工作?我正在学习,所以如果有人解释事情会很棒。谢谢。

4

3 回答 3

3

那是因为i当你给的回调setTimeout被调用时,它的值是循环结束。

一个解决方案是将其更改为

function say(str){
    for(i=0;i<str.length;i++){
        (function(i){
          setTimeout(function(){
            $("#text").append(str[i]);
          },
          i*200);
        })(i);
    }
}

i这会将迭代时的值保存在立即调用的内部函数中。

于 2013-05-24T16:39:48.897 回答
2

我不建议使用for循环并尝试让实际时间排队。递归调用一个函数setTimeout对我来说更有意义,并且不会遇到你遇到的闭包问题。您可以使用:

function say(str) {
    (function iterator(index) {
        if (index < str.length) {
            $("#text").append(str.charAt(index));
            console.log(str.charAt(index));
            setTimeout(function () {
                iterator(++index);
            }, 200);
        }
    })(0);
}
say("Hello World !");

演示:http: //jsfiddle.net/XnKNX/6/

.charAt()是获取字符串字符的首选方式,因为旧版 IE 不支持[]索引。

如果你想保持for循环(无论出于何种原因),你可以这样设置:

var say = (function () {
    var generateTyper = function (s, index) {
        return function () {
            $("#text").append(s.charAt(index));
            console.log(s.charAt(index));
        };
    };
    return function (str) {
        for (var i = 0, j = str.length; i < j; i++) {
            setTimeout(generateTyper(str, i), i * 200);
        }
    };
})();
say("Hello World !");

演示:http: //jsfiddle.net/8kxFd/1/

于 2013-05-24T16:43:03.280 回答
1

在寻找要在我的网站上使用的脚本时,我偶然发现了这个问题。找了好久,决定自己写。

这是 Github 上的链接,希望它可以帮助某人:)

简要说明

class Typer {

    constructor(typingSpeed, content, output) {

        this.typingSpeed = typingSpeed;
        // Parses a NodeList to a series of chained promises
        this.parseHtml(Array.from(content), output);
    };

    makePromise(node, output) {

        if (node.nodeType == 1) // element 
        {
            // When a new html tag is detected, append it to the document
            return new Promise((resolve) => {
                var tag = $(node.outerHTML.replace(node.innerHTML, ""));
                tag.appendTo(output);
                resolve(tag);
            });

        } else if (node.nodeType == 3) // text
        {
            // When text is detected, create a promise that appends a character
            // and sleeps for a while before adding the next one, and so on...
            return this.type(node, output, 0);
        } else {
            console.warn("Unknown node type");
        }
    }

    parseHtml(nodes, output) {
        return nodes.reduce((previous, current) => previous
            .then(() => this.makePromise(current, output)
                .then((output) => this.parseHtml(Array.from(current.childNodes), output))), Promise.resolve());
    }

    type(node, output, textPosition) {
        var textIncrement = textPosition + 1;

        var substring = node.data.substring(textPosition, textIncrement);

        if (substring !== "") {
            return new Promise(resolve => setTimeout(resolve, this.typingSpeed))
                .then(() => output.append(substring))
                .then(() => this.type(node, output, textIncrement));
        }

        return Promise.resolve(output);
    }
}
于 2017-02-09T12:54:40.007 回答