Почему я не могу переключить курсор на прогресс до выполнения какого-либо скрипта в jQuery?

Я изо всех сил пытался понять, что я здесь делаю не так. Я просто пытаюсь изменить курсор на «прогресс» с помощью функции jQuery .css() после того, как пользователь нажимает кнопку, но перед циклическим переходом через серию в HighStock (выполнение которой занимает пару секунд) и отображение / скрытие некоторых строк (32 из них !).

Я пробовал много вещей, но что бы я ни пробовал, он просто останавливает кнопку в положении «вниз» (не меняя курсора, но вы все равно можете перемещать его) до тех пор, пока код не будет завершен.

Вот что я пробовал (по порядку):

Примечание. Все мои попытки дают одни и те же результаты (т. е. ошибок не возникает, код выполняется, но я никогда не получаю курсор "прогресс", который отображается, пока код занят. выполнено.

$("#onAllOverall").click(function () {
    $("body").css("cursor", "progress");

    for (var s = 0; s < series.length; s++) {
        series[s].hide();
    }

    $("body").css("cursor", "default");
});

Итак, я попробовал:

$("#onAllOverall").click(function () {
    $("body").css("cursor", "progress");
}

$("#onAllOverall").click(function () {
    for (var s = 0; s < series.length; s++) {
        series[s].hide();
    }

    $("body").css("cursor", "default");
});

Я даже дошел до того, что попробовал:

function progressCursor() {
    $("body").css("cursor", "progress");
}

$("#onAllOverall").click(function () {

    $.when(progressCursor).done(function () { //also tried $.when.then(), but I admit I don't know much about these methods;
        for (var s = 0; s < series.length; s++) {
            series[s].show();
        }
    });

    $("body").css("cursor", "default");
});

Я помню, как пробовал еще пару вещей, но не могу точно вспомнить, что они были, но они были простыми и бесполезными.

Я чувствую себя глупо, что здесь ничего не работает. Что я делаю неправильно?


person VoidKing    schedule 27.03.2014    source источник
comment
похоже, что поток пользовательского интерфейса был заблокирован во время цикла. Вы должны сделать for async, используя timeInterval   -  person Warlock    schedule 27.03.2014
comment
что это за серия? Допустимый ли объект для запуска функции "Показать и скрыть"?   -  person TheMohanAhuja    schedule 27.03.2014
comment
@TheMohanAhuja это функция плагина HighStock   -  person VoidKing    schedule 27.03.2014


Ответы (1)


Вам нужно будет «передать» цикл событий браузеру, чтобы он мог отобразить страницу (включая изменение курсора) во время цикла for.

Самый простой способ выхода в браузере - установить время ожидания 0 мс. (В Nodejs есть функция nextTick, которая вам и нужна, но браузеры ее еще не реализовали.)

$("#onAllOverall").click(function () {
    $("body").css("cursor", "progress");
    var s = 0;
    function next(){
        series[s].hide();
        s++;
        if(s < series.length){
            setTimeout(next, 0);
        } else {
            $("body").css("cursor", "default");
        }
    }
    if(series.length){
        next();
    }           
});

Для этих целей отлично подходит библиотека https://github.com/caolan/async.

Обратите внимание, что эта реализация выдает результат после каждого события hide (). Вы можете обнаружить, что он работает только с одним набором тайм-аута, оборачивающим цикл for. Уступка после каждой операции сделает страницу более отзывчивой во время выполнения цикла, но также может привести к тому, что страница будет выглядеть странно, поскольку каждый элемент будет исчезать по одному.

Чтобы он не сдавался после каждого действия:

$("#onAllOverall").click(function () {
    $("body").css("cursor", "progress");

    function action(){
       for (var s = 0; s < series.length; s++) {
          series[s].hide();
       }

       $("body").css("cursor", "default");
    }
    setTimeout(action, 0);       
});
person Will Shaver    schedule 27.03.2014
comment
Хорошо, я попробовал это, и это работает, но я не уверен на 100%, что знаю, почему. Увидев его в действии, я могу сказать, что предпочел бы, чтобы он не сдавался после каждого hide() события. Можете ли вы показать пример, в котором он работает только с одним набором тайм-аута, оборачивающим цикл for? - person VoidKing; 27.03.2014
comment
Если series.length равен нулю, цикл запускать не нужно. if (series.length) гарантирует, что он больше нуля. - person Will Shaver; 27.03.2014
comment
Да, извините, я увидел это сразу после того, как опубликовал, а затем удалил комментарий :) Спасибо за объяснение и большое спасибо за другой пример. У вас это работает для меня, но что я действительно очень ценю, так это то, что я учусь на ваших примерах и почему они сработали. Еще раз спасибо! - person VoidKing; 27.03.2014
comment
Так эффективно, все, что вы здесь делаете, превращаете action в асинхронную функцию? Это правильно? - person VoidKing; 27.03.2014
comment
О нет, вы не поверите, но ваш второй пример (тот, который мне нужен) не работает. Он по-прежнему просто блокирует интерфейс и не показывает курсор выполнения. - person VoidKing; 27.03.2014
comment
Я настоятельно рекомендую вам ознакомиться с циклом событий javascript. Вам нужно уступить браузеру, чтобы он смог выполнить рендеринг. Это займет свою очередь вместе со всем вашим кодом javascript. - person Will Shaver; 27.03.2014
comment
Попробуйте отрегулировать тайм-аут. - person Will Shaver; 27.03.2014
comment
Хорошо, это странно, но это работает, только если я перемещаю мышь на количество миллисекунд, указанное в тайм-ауте. Если я буду удерживать мышь, она останется замороженной, даже если я передвину ее после срабатывания тайм-аута. Есть ли какое-то решение для этого? - person VoidKing; 27.03.2014
comment
К сожалению нет. stackoverflow.com/questions/1718415/ Я бы порекомендовал изменить что-то другое на странице вместо курсора. - person Will Shaver; 27.03.2014
comment
Думаю, ты прав, это, наверное, лучше всего, но твой первый вариант выглядит более привлекательным теперь, когда я знаю, какую работу мне пришлось бы вложить во второй, лол. - person VoidKing; 27.03.2014