Используйте рекурсию вместо EVAL - PullRequest
3 голосов
/ 17 ноября 2009

У меня есть список элементов на странице, которые должны быть последовательно скрыты, но сразу после того, как предыдущий элемент был полностью скрыт.

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

// get items to hide
    var itemsToHide = jQuery(".hide");

// function responsible to hide the item
    var hideItem = function (item, callback) {
     jQuery(item).hide(100, callback)
    };

// declare an empty function, to be the first to be called
    var buff = function(){};

    for (var i = 0; i < itemsToHide.length; i++) {
// put the previous value of buff in the callback and assign this to buff
     buff = "function(){hideItem(itemsToHide[" + i + "], " + buff + ");}";
    }

// execute the effects
    eval("(" + buff + ")()");

Любое предложение о том, как добиться этого эффекта с помощью рекурсии, без "злого" пробуждения?

Ответы [ 2 ]

7 голосов
/ 17 ноября 2009

Скрытие с рекурсией - функциональный стиль

В этом случае вы знаете длительность эффекта, поэтому вы можете делать то, что предлагали другие.

Однако вы все равно можете знать, как добиться того же, используя более функциональный стиль и простую рекурсию.

Итак, я покажу вам, как это сделать.

1. Код

<script src="http://code.jquery.com/jquery-latest.pack.js"></script>
<script type="text/javascript">
    $(function() {
        var items = jQuery(".to-hide");
        (function hideRec() {
            if (items.length == 0) {
                window.alert("The end.");
                return;
            }
            var toHide = jQuery(items[0]);
            items = items.slice(1);
            toHide.hide("100", hideRec);
        })();
    });
<script>

<ul>
    <li class="to-hide">...</li>
    <li class="to-hide">...</li>
    <li class="to-hide">...</li>
    <li class="to-hide">...</li>
    <li class="to-hide">...</li>
<ul>

2. Как это работает?

Сначала мы получаем из jQuery массив, содержащий нужные нам объекты to-hide.

Затем мы создаем именованную анонимную функцию , которая будет выполняться сразу после ее определения - это шаблон (function() { ... })();. Даже если это анонимная функция , мы даем ей имя, чтобы мы могли легко вызывать ее рекурсивно.

Обратите внимание, что вы можете достичь того же самого, не называя анонимной функции имя - что может показаться немного странным, если вы не понимаете, как JavaScript работает с областью действия - с более неясной версией:

(function() {                            // Anonymous function without a name
    if (items.length == 0) {
        window.alert("The end.");
        return;
    }
    var toHide = jQuery(items[0]);
    items = items.slice(1);
    toHide.hide("100", arguments.callee); // Recursive call to anonymous function
})();

На этот раз мы использовали тот факт, что arguments.callee представляет саму функцию - поэтому нет необходимости давать имя анонимной функции.

Вся магия находится внутри этой рекурсивной анонимной функции - это закрытие.

Анонимная функция hideRec захватывает массив items. После проверки того, что внутри что-то есть, он удалит первый элемент и сохранит его в локальной переменной toHide (правильно обернутой в jQuery).

В конце он использует jQuery, чтобы скрыть элемент, и передает эту анонимную функцию в качестве обратного вызова - jQuery будет вызывать ее снова после завершения эффекта.

Надеюсь, это достаточно ясно.

Удачи!

3 голосов
/ 17 ноября 2009

Поскольку вы знаете количество миллисекунд, которые каждая из них скрывает, вам вообще не нужно использовать обратный вызов:

jQuery(".hide").each(function(i)
{
    var obj = $(this);
    setTimeout(function() { obj.hide(100); }, i * 100);
}
...