2012-05-15 38 views
2

大胆表示更新。实现了遍历数组的一个跑步者

我有一个数组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]可以在步骤[1]中创建与dom元素(,通过AJAX)进行交互,所以跑步者需要等待特定的时间段(因此超时),轮询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

不''代表一个jQuery对象,或用作jQuery选择只是一个CSS选择器?如果它已经是一个jQuery对象,那么当新元素添加到DOM时不会更新... –

+0

谢谢。目前它是一个jqueryobject我将不得不更新,以使用选择器。 –

+0

如果您的选择器是一个类选择器,并且该类的页面上还有其他元素,那么您如何知道前一个函数是否已完成其作业? –

回答

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); 

在这里看到它在行动:http://jsfiddle.net/myaeh/

+0

很酷。我已经放弃了。 –

+0

@kennethkoontz - 我更新了一下代码(我有一些遗漏),并包括一个小提琴。希望它适合你... –

+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()函数定义使用setInterval继续检查当前元素是否可见一个nextStep()功能。一旦完成,它将执行操作,清除间隔,然后通过setTimeout调用自身,继续前进到下一个元素。

我不确定如何在轮询中使用超时概念,因为如果当前元素在指定的时间量之后不可见,你会怎么做?你不能继续下一个元素,因为它也可能依赖于前面的步骤。我想你可以通过清除间隔和而不是再次调用nextStep()来终止整个事情。 编辑:我已更新的代码工作,按最后一句话。

+0

对不起。我应该更清楚地说,点击任何元素,都可以通过ajax创建一个dom元素。我会更新帖子。 –

+0

此外,为了澄清这个问题,“如果当前元素在指定的时间量之后不可见,你会做什么?”,跑步者会中止。 –

+0

好的,我已经对代码进行了一些更新,以便在任何给定步骤超时的情况下中止整个事件。此外,我已经将它改为假设每个步骤的'element'属性都是jQuery _selector_,而不是jQuery _object_,因此您可以在之前的步骤中为由ajax创建的元素指定选择器。 – nnnnnn