BOLD 表示更新。
我有一个数组steps
,其内容是具有与之关联的动作和元素的对象。像这样:
steps = [{action: 'click', element: <jQuery element>},
{action: 'click', element: <jQuery element>}, ., ., N]
我想实现一个运行器,它的作用是遍历数组中的每个元素并对元素执行特定操作。每个步骤必须连续执行。例如,如果你有:
steps = [{action: 'click', element: <jQuery element representing a button>},
{action: 'click', element: <jQuery element representing an anchor tag>}]
运行run(steps, timeout)
,将贯穿每一步。步骤[0] .action将在步骤[0] .element上执行。由于步骤[0]可以创建dom元素(通过AJAX )以在步骤[1]中进行交互,因此跑步者需要等待特定时间段(因此,超时) ),调查dom是否存在步骤[1]。元素。
这是我迄今为止所做的粗略看法:
var run = function() {
$.each(steps, function(i, v) {
var interval = 25,
start = 0,
timeout = 3000;
var i = setInterval(function(timeout) {
start = start + interval;
console.log(start);
if ($(v).is(':visible')) {
v.click();
console.log('clicked', v);
clearInterval(i);
}
}, interval);
});
};
请注意,在上面的示例中,steps
只是一个jquery对象数组。它还没有达到理想的格式:
steps = [{action: 'click', element: <jQuery element>},
{action: 'click', element: <jQuery element>}, ., ., N]
这样的'模式'是什么,我需要遵循?我是否需要使用延迟对象来处理这个问题?它是用setTimeout,setInterval实现的吗?谢谢!
最终实施
var run = function(steps, interval, timeout) {
var timer,
time = 0,
i = 0;
runSingle(steps[0]);
function abort() {
console.log("Run aborted");
}
function runSingle(step) {
timer = setInterval(function() {
time += interval;
if ($(step.element).is(':visible') === true) {
clearInterval(timer);
time = 0;
$(step.element).trigger(step.action);
(i < (steps.length - 1)) && runSingle(steps[++i]);
} else if (time >= timeout) {
clearInterval(timer);
abort();
}
}, interval);
console.log("Performed: ", step.action, "on", step.element)
if (i === (steps.length - 1)) console.log("Run successful");
}
}
答案 0 :(得分:1)
首先请注意,在您的示例中,v
变量将代表数组中的对象,因此说v.click()
或$(v).is(':visible')
没有意义 - 您需要想说v.element.click()
或v.element.is(':visible')
。
如果你的意思是action
将是一个jQuery方法名称的字符串,并且element
是一个jQuery对象,那么你可以这样做:
$.each(steps, function(i, obj) {
obj.element[obj.action]();
});
如果element
是表示应该用于创建jQuery对象的选择器的字符串,那么:
$.each(steps, function(i, obj) {
$(obj.element)[obj.action]();
});
除非action
可以异步执行某些操作,否则不需要引入轮询概念,例如,如果它执行淡入,或通过Ajax添加元素。
在您的示例中,您似乎申请是否继续当前步骤的唯一标准是当前元素是否可见。如果是这种情况,你可以这样做:
var run = function(steps, delay, timeout) {
var i = 0,
nextStep = function() {
if (i < steps.length) {
var step = steps[i],
retryDelay = 25,
retryTotal = 0,
intervalId = setInterval(function() {
retryTotal += retryDelay;
var $el = $(step.element);
if ($el.is(':visible')) {
$el[step.action]();
clearInterval(intervalId);
i++;
setTimeout(nextStep, delay);
} else if (retryTotal >= timeout) {
clearInterval(intervalId);
}
}, retryDelay);
};
}
nextStep();
};
run(steps, 50, 3000);
run()
函数定义nextStep()
函数,该函数使用setInterval
来检查当前元素是否可见。一旦完成,它将执行操作,清除间隔,并通过setTimeout
调用自身来移动到下一个元素。
我不确定如何在轮询中使用超时概念,因为如果当前元素在指定的时间后不可见,您会做什么?你不能真正继续下一个元素,因为它也可能取决于之前的步骤。我想你可以通过清除间隔并且不再次调用nextStep()
来中止整个事情。 编辑:我已根据最后一句更新了代码。
答案 1 :(得分:1)
这是件事。我没有彻底测试过:
var run = function(steps, interval)
{
var timer,
time = 0, timeout = 10000,
ciel = steps.length - 1,
i = 0;
run_single(steps[0]);
function run_single(item)
{
timer = setInterval(function()
{
var $el = $(item.selector);
time += interval;
if ( $el.length )
{
clearInterval( timer );
time = 0;
$el.trigger( item.action );
i < ciel && run_single( step[ ++i ] );
}
else
{
if ( time >= timeout ) clearInterval( timer );
}
}, interval);
}
};
var steps = [
{action: 'click', selector: '#first'},
{action: 'hover', selector: '#second'},
{action: 'change', selector: '#third'}
// and so on...
];
run(steps, 100);
在此处查看:[{3}}