我正在开发一个 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,就应该触发第二个调用。一旦声音完成(即延迟),就会触发第三个脚本。动画完成后应触发第四个函数。第五个事件应该在事件(例如单击)上触发。
对此的一个技术解决方案是在前一个函数的回调中调用该函数,这可能会变得非常困惑。我喜欢一个解决方案,其中的功能被称为精简版,这是一个有一点头脑但没有编码经验的人可以敲出自己的脚本的地方。你会如何解决这个问题?我对 javascript 还很陌生,所以如果您能明确说明,我将不胜感激。
最佳答案
我会使用预构建的解决方案。一定会有一款适合您的需求。简单的东西,比如 jTour或者如果这不能涵盖它一些更复杂的东西,例如 Scriptio 。 this question的一些答案您可能也感兴趣。
编辑 如果您不想使用预先存在的解决方案,我会这样做:
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
会为他们处理该问题。与需要编写器管理回调的系统相比,这具有一些很大的优势。您不需要像使用显式回调那样为脚本中的每一行使用唯一的名称,也不需要无休止地嵌套匿名函数。您不需要重新连接任何内容来更改命令的播放顺序,只需在数组中物理地重新排列它们即可。
您的每个命令都需要等待其操作完成,然后才能调用其回调(也称为 this
)。我使用 setTimeout 在 fiddle 中模拟这一点。例如,如果您使用 jQuery 的 .animate
对于 highlight
,它提供了一个 complete
处理程序,该处理程序在动画完成时触发,只需粘贴 this
(不带调用括号 ( )
) 在那里。如果您使用 jQuery UI,它有一个内置的 'highlight' effect ,所以你可以像这样实现它:
highlight: function (selector) {
//animation that highlights an element.
$(selector).effect('highlight', 'slow', this);
},
大多数提供动画的其他库应该提供您可以使用的类似回调选项。
控制声音的回调可能会更困难,具体取决于您播放声音的方式。如果您使用的方法不提供回调或轮询以查看是否完成的方法,那么您可能只需要向 playsound
添加另一个参数,该参数将声音的长度设置为ms,然后等待那么长时间才继续:
playsound: function (soundPath, soundLength) {
//playing a sound (duh)
setTimeout(this, soundLength);
},
关于javascript - 我应该如何在 javascript 中制作复杂的连续事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15101243/