2

我正在开发一个用于 JavaScript 的交互式教程工具。该工具的核心是教程的脚本。该脚本将触发运行动画、扬声器声音加载新页面等的各种功能。三个示例调用(大多数教程将有 10-100 次调用,因此非常需要对调用进行简洁的概述:

wrap(); //wrap the page in an iframe
playsound('media/welcome') //playing a sound (duh)
highlight('[name=firstname]'); //animation that highlights an element.
playsound('media/welcome2');
loadpage(page2); //loading a new page

所有调用都有一个共同点:它们都有非正常触发器。例如,在这个简单的脚本中,一旦加载了第一个调用中的 iframe,就应该触发第二个调用。一旦声音完成(即延迟),就会触发第三个脚本。动画完成后应该触发第四个功能。第五个事件应该在一个事件上触发(例如点击)。

对此的技术解决方案是在前一个函数的回调中调用该函数,这可能会变得非常混乱。我喜欢这样的解决方案,其中函数被称为 lite,这是一个有一点头脑但没有编码经验的人可以编写自己的脚本。你会如何解决这个问题?我对javascript很陌生,所以如果你能明确一点,我会很感激的。

4

2 回答 2

2

我认为回调是你最好的选择。它们不必是凌乱的(尽管当然有可能使它们完全难以理解)。您可以创建每个函数来接受回调,然后使用这样的结构以可读的方式依次调用它们:

var loadingSequence = {
    start : function() { wrap(this.playsound); },
    playsound : function() { playsound('media/welcome', this.highlight); },
    highlight : function() { highlight('[name=firstname]', this.playsound2); },
    playsound2 : function() { playsound('media/welcome2', this.loadpage); },
    loadpage : function()  { loadpage(page2); }
};

loadingSequence.start();
于 2013-02-26T23:17:42.317 回答
2

我会使用按构建的解决方案。一定有一款适合您的需求。像jTour这样简单的东西,或者如果不包括它,像Scriptio这样更复杂的东西。您可能也对这个问题的一些答案感兴趣。

编辑 如果您不想使用预先存在的解决方案,我会这样做:

var runTutorial = (function () {

    // The command object holds all the different commands that can
    // be used by someone for the tutorial. Each of these commands
    // will recive a callback set as their `this`. This
    // callback should be called by your commands when they are done
    // running. The person making the tutorial won't need to know
    // about the callback, the code will handle that.
    var commands = {
        wrap: function () {
            //wrap the page in an iframe
            this();
        },
        playsound: function (soundPath, soundLength) {
            //playing a sound (duh)
            setTimeout(this, soundLength);
        },
        highlight: function (selector) {
            //animation that highlights an element.
            //I'm using jQuery UI for the animation here,
            // but most animation libraries should provide
            // a callback for when the animation is done similarly
            $(selector).effect('highlight', 'slow', this);
        },
        loadpage: function (pageUrl) {
            //loading a new page
            setTimeout(this, 500);
        },
        waitForClick: function () {
            // when we go into the click handler `this` will no
            // longer be availble to us since we will be in a
            // different context, save `this` into `that` so
            // we can call it later.
            var that = this;
            $(document).one('click', function () {
                that();
            });
        }
    },
    // This function takes an array of commands
    // and runs them in sequence. Each item in the
    // array should be an array with the command name
    // as the first item and any arguments it should be
    // called with following as the rest of the items.
    runTutorial = function (commandList) {
        var nextCommand = function () {
            if (commandList.length > 0) {
                var args = commandList.shift();

                // remove the command name
                // from the argument list
                cmd = args.shift(1);

                // call the command, setting nextCommand as `this`
                commands[cmd].apply(nextCommand, args);
            }
        }

        nextCommand();
    };

    return runTutorial;

}()); 

$('#tutorialbutton').click(function() {
    runTutorial([
        ['playsound', 'media/welcome', 1000],
        ['highlight', '[name=firstname]'],
        ['playsound', 'media/welcome2', 1500],
        ['waitForClick'],
        ['loadpage', page2],
        ['playsound', 'media/page2', 100]
    ]);
});

runTutorial函数采用一个简单的数组,其中包含按应运行顺序排列的命令及其参数。无需用回调来打扰编写脚本的人runTutorial,为他们处理。与需要编写器管理回调的系统相比,这具有一些很大的优势。您不需要像使用显式回调那样为脚本中的每一行指定一个唯一的名称,也不需要无休止地嵌套匿名函数。您无需重新连接任何东西来更改命令的播放顺序,您只需在阵列中重新排列它们即可。

你可以玩的jsfiddle

您的每个命令都需要等待其操作完成,然后才能调用其回调(又名this)。我在小提琴中使用setTimeout. 例如,如果您使用 jQuery 的.animatefor highlight,它提供了一个complete在动画完成时触发的处理程序,只需坚持this(不带调用括号())在那里。如果您使用的是 jQuery UI,它具有内置的“高亮” 效果,因此您可以像这样实现它:

highlight: function (selector) {
    //animation that highlights an element.
    $(selector).effect('highlight', 'slow', this);
},

大多数其他提供动画的库应该提供类似的回调选项,您可以使用。

根据您播放它们的方式,控制声音的回调可能会更难。如果您使用的方法没有提供回调或轮询它的方式以查看它是否已完成,您可能只需要添加另一个参数,playsound该参数以毫秒为单位获取声音的长度,然后在继续之前等待那么长时间:

playsound: function (soundPath, soundLength) {
    //playing a sound (duh)
    setTimeout(this, soundLength);
},
于 2013-02-26T23:38:59.977 回答