2014-02-03 5 views
0

На самом деле это проблема, которая была создана при попытке ответить на другой вопрос: https://stackoverflow.com/questions/21517910/remove-elements-in-reverse-order/SetTimeout остановка после одного выполнения функции

я предоставил псевдокод и Дерек 朕 會 功夫 при условии кода. Однако, когда я хотел добавить короткую задержку в код, чтобы мы могли видеть, что происходит, он прекращает выполнение правильно. SetTimeOut останавливается после одного выполнения.

Fiddle: http://jsfiddle.net/UFfHX/

JQuery Код:

function RemoveNode(node) { 
    for (var i = node.children.length - 1; i >= 0; i--) { 
     setTimeout(RemoveNode(node.children[i])); 
    } 
    $(node).remove(); 
} 

RemoveNode($(".parent")[0]); 

Я попытался с помощью window.setTimeout() и используя function(){} внутри с вызовом, чтобы удалить узел, но это не сработало. В то же время, этот код выполняется правильно:

function RemoveNode(node){ 
    for(var i = node.children.length - 1; i >= 0; i--){ 
     RemoveNode(node.children[i]); 
     alert("hi"); 
    } 
    $(node).remove(); 
} 

RemoveNode($(".parent")[0]); 

EDIT: Чтобы уточнить, я хочу добавить 2s ждать перед каждым вызовом RemoveNode в примере ниже.

function RemoveNode(node) { 
    for (var i = node.children.length - 1; i >= 0; i--) { 
     //Something like sleep(2000); 
     RemoveNode(node.children[i]); 
    } 
    $(node).remove(); 
} 

RemoveNode($(".parent")[0]); 
+0

Ваш пост код, который не работает? ваши комментарии говорят, что вы добавили функцию() {} stuff .. измените свое сообщение как код, который НЕ работает. –

+0

'setTimeout()' требует функции, которую нужно передать, в то время как вы проходите в результате функция. –

+0

Это код, который не работает. Он должен удалить всю верхнюю бокс в jfiddle с интервалом в 2 с перед каждым вызовом для функции RemoveNode. Но он останавливается после 1 вызова, если я использую setTimeout. – Xyzk

ответ

2

Если то, что вы пытаетесь сделать, это удалить DOM детей медленно, то вот простой пример того, как сделать это с помощью таймера:

function removeSlowly() { 
    function removeNext() { 
     var item = $("#top li:last").remove(); 
     if (item.length) { 
      setTimeout(removeNext, 1000); 
     } 
    } 
    removeNext();  
} 

Что касается замечаний по ваш текущий код:

Вы должны передать ссылку на функцию setTimeout(), и вам необходимо передать значение времени в качестве второго аргумента, и вы должны иметь правильное количество подходящих паренов.

Итак, код изменения, как это:

setTimeout(RemoveNode(node.children[i]); 

к:

setTimeout(function() { 
    RemoveNode(node.children[i]); 
}, 1000); 

При попытке просто передать RemoveNode(node.children[i]), вы выполняете эту функцию сразу (это в круглые скобки делают), а затем передавая результат возврата от выполнения до setTimeout(). Поскольку возвращаемое значение не является функцией, для `setTimeout() нет ничего, поэтому ваша функция вызывается только один раз.

FYI, у вас также есть всевозможные синтаксические ошибки (отсутствующие парсы и отсутствующие аргументы), поэтому вам нужно очистить все это в остальной части вашего кода.


Кроме того, даже после того, как вы исправить ваш setTimeout() код здесь, у вас есть несколько логических задач здесь:

function RemoveNode(node) { 
    for (var i = node.children.length - 1; i >= 0; i--) { 
     setTimeout(function() { 
      RemoveNode(node.children[i]); 
     }, 1000); 
    } 
    $(node).remove(); 
} 

Во-первых, значение i не будет правильным внутри функции обратного вызова setTimeout() потому что цикл for будет уже закончен, так что i будет иметь значение в конце цикла. Это можно зафиксировать закрытием.

Затем вы пытаетесь вызвать RemoveNode() на детей после того, как вы уже удалили родителя. В чем смысл этого? Дети уже удалены из DOM.

Вы можете исправить эту проблему с помощью i следующим образом, но я не уверен, что пришло, что вы вызываете RemoveNode для детей вообще, когда они уже удалены из DOM.

function RemoveNode(node) { 
    for (var i = node.children.length - 1; i >= 0; i--) { 
     (function(index) { 
      setTimeout(function() { 
       RemoveNode(node.children[index]); 
      }, 1000); 
     })(i); 
    } 
    $(node).remove(); 
} 
+0

Посмотрите на выполнение кода, используя мой второй фрагмент кода (тот, у кого есть предупреждение). Он удаляет 1 div, ждет, пока вы не примете предупреждение, удалите второй div, ждет, пока вы не примете другое предупреждение. Я хочу, чтобы он работал одинаково, но вместо того, чтобы нажимать «ok» в всплывающей кнопке, я хочу, чтобы код переставал исполняться на секунду. – Xyzk

+0

@Xyzk - 'alert()' приостанавливает выполнение JS, которое невозможно любым другим способом. Вы можете создать таймер, который удалит один элемент DOM для каждого тика. Я приведу простой пример. – jfriend00

+0

@Xyzk - вот демо детей DOM, которые удаляются медленно: http: // jsfiddle.net/jfriend00/7yF2T/ – jfriend00

1

Чтобы дополнить то, что jfriend00 уже сказал, что все правильно, вы можете посмотреть на это: jsfiddle.

Я не уверен, как далеко вы хотите, чтобы удаление возвращалось вверх по дому и ваше точное намерение в отношении способа удаления, но это удалит листовые узлы и один родитель каждые две секунды. Он показывает, как использовать setTimeout и рекурсию.

var interval = 2000; 
    function RemoveNode($node) { 
     if($node.children().length > 0) 
     { 
      $node.children().each(function(){      
       RemoveNode($(this));   
      }); 
     } 
     else 
     {    
      setTimeout(
       function() 
       {            
        var $parent = $node.parent(); 
        $node.remove(); 
        if($parent.children().length == 0) 
        {      
         $parent.remove(); 
        } 
       }, 
       interval 
      ); 
      interval += 2000;   
     } 
    } 
    RemoveNode($(".parent")); 

Update

Смотрите так: jsfiddle.

Это приведет к удалению элементов по одному, если они имеют класс removable. Класс removable так, что мы не удаляем каждый элемент вверх по дереву, например li и ul один за другим. Если вы хотите, чтобы оба родителя удалялись параллельно, выведите .first() из кода.

var interval = 2000; 
function RemoveNode($node) { 
    var $removable = $node.find('.removable').first(); 
    if($removable.length > 0) 
    { 
     RemoveNode($removable); 
    } 
    else if($node.hasClass('topParent') == false) 
    {   
     //this is a leaf removable node. 
     setTimeout(
      function() 
      {           
       var $parent = $node.parent().closest('.removable');         
       $node.remove(); 
       RemoveNode($parent);     
      }, 
      interval 
     );      
    } 
} 
RemoveNode($(".topParent")); 

HTML:

<div class="topParent removable"> 
    <div class="parent removable"> 
     <div class="second removable"> 
      <div class="third removable"> 
       <ul class="removable"> 
        <li>Hey</li> 
       </ul> 
       <ul class="removable"> 
        <li>Hey 1</li> 
       </ul> 
       <ul class="removable"> 
        <li>Hey 2</li> 
       </ul> 
      </div> 
     </div> 
    </div> 
    <div class="parent removable"> 
     <div class="second removable"> 
      <div class="third removable"> 
       <ul class="removable"> 
        <li>Hey</li> 
       </ul> 
       <ul class="removable"> 
        <li>Hey 1</li> 
       </ul> 
       <ul class="removable"> 
        <li>Hey 2</li> 
       </ul> 
      </div> 
     </div> 
    </div> 
</div> 
+0

Идея заключалась в том, что функция удаляет все элементы внутри первого вызывающего узла (в этом случае удаляет всех дочерних узлов «родительских» узлов и самого родительского узла). – Xyzk

+0

@Xyzk - см. Мое обновление – acarlon

Смежные вопросы