Javascript - индикатор загрузки/занятости или прозрачный div поверх страницы при нажатии события

У меня есть функция javascript на стороне клиента, которая запускается нажатием кнопки (в основном, калькулятор!). Иногда из-за огромных данных на странице функция калькулятора javascript занимает много времени и делает страницу неактивной для пользователя. Я планировал отображать прозрачный div поверх всей страницы, возможно, с индикатором занятости (в центре), пока функция калькулятора не закончится, так что пользователь ждет, пока процесс не закончится.

function CalculateAmountOnClick() {
  // Display transparent div

  // MY time consuming loop!
    {

    }

  // Remove transparent div 

}

Любые идеи о том, как это сделать? Должен ли я назначать класс css для div (который охватывает все содержимое страницы) с помощью javascript, когда начинается моя калькулятор? Я пробовал это, но не получил желаемых результатов. Возникла проблема с прозрачностью в IE 6. Также как я покажу загрузочное сообщение + изображение в таком прозрачном div?

ТИА

Ответ 1

Javacript, чтобы показать занавес:

function CalculateAmountOnClick () {
  var curtain = document.body.appendChild( document.createElement('div') );
  curtain.id = "curtain";
  curtain.onkeypress = curtain.onclick = function(){ return false; }
  try {
    // your operations
  }
  finally {
    curtain.parentNode.removeChild( curtain );
  }
}

Ваш CSS:

#curtain {
  position: fixed;
  _position: absolute;
  z-index: 99;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  _height: expression(document.body.offsetHeight + "px");
  background: url(curtain.png);
  _background: url(curtain.gif);
}

(Переместите MSIE 6 подшивки для условно включенных файлов по желанию.)

Вы можете установить это как функции добавления/удаления для занавеса или в качестве обертки:

function modalProcess( callback ) {
  var ret;
  var curtain = document.body.appendChild( document.createElement('div') );
  curtain.id = "curtain";
  curtain.onkeypress = curtain.onclick = function(){ return false; }
  try {
    ret = callback();
  }
  finally {
    curtain.parentNode.removeChild( curtain );
  }
  return ret;
}

Что вы могли бы тогда вызвать следующим образом:

var result = modalProcess(function(){
  // your operations here
});

Ответ 2

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

Браузер не перерисовывается при каждом обновлении DOM. Это может означать, что вы делаете что-то еще, а затем рисуете то, что необходимо (браузеры меняют свой метод для этого). Таким образом, в этом случае он может обновлять дисплей только после того, как он удалил занавес, или вы заставили перерисовать путем прокрутки.

Справедливая дератизация: эта интенсивная обработка не очень приятна вам, потому что она не только блокирует вашу страницу. Поскольку браузеры обычно реализуют только один поток Javascript для ВСЕХ вкладок, ваша обработка заблокирует все открытые вкладки (= браузер). Кроме того, вы рискуете временем ожидания выполнения и браузером, просто остановив свой script (это может быть всего 5 секунд).

Вот как это сделать.

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

function processLoop( actionFunc, numTimes, doneFunc ) {
  var i = 0;
  var f = function () {
    if (i < numTimes) {
      actionFunc( i++ );  // closure on i
      setTimeout( f, 10 )
    } 
    else if (doneFunc) { 
      doneFunc();
    }
  };
  f();
}

// add a curtain here
processLoop(function (i){
  // loop code goes in here
  console.log('number: ', i);
}, 
10,  // how many times to run loop
function (){
  // things that happen after the processing is done go here
  console.log('done!');
  // remove curtain here
});

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

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

// add a curtain
var curtain = document.body.appendChild( document.createElement('div') );
curtain.id = "curtain";
curtain.onkeypress = curtain.onclick = function(){ return false; }
// delay running processing
setTimeout(function(){
  try {
    // here we go...
    myHeavyProcessingFunction();
  }
  finally {
    // remove the curtain
    curtain.parentNode.removeChild( curtain );
  }
}, 40);

Если вы используете js-библиотеку, вы можете посмотреть готовое решение для создания занавесок. Они должны существовать для большинства библиотек, вот для jQuery, и они могут помочь с CSS.

Ответ 3

Я бы сделал somthing like:

1.недвойте div (дисплей: встроенный)

2.Вставьте положение: абсолютное

3. Дайте ему z-индекс: 99

4. Сделайте высоту и ширину 100%

5. Когда обработка выполнена, установите отображение: none

Чтобы сделать его прозрачным, вам нужно установить прозрачность, которая отличается от ff и т.д.

Чтобы показать значок загрузки, вы всегда можете создать второй div и поместить его там, где хотите на странице. Когда он будет загружен, удалите его вместе с прозрачным.

Ответ 4

В дополнение ко всему вышесказанному, не забудьте поставить невидимый iframe за прокладку, чтобы он отображался над блоками выбора в IE.

Изменить: Этот сайт, хотя он и обеспечивает решение более сложной проблемы, охватывает создание модального фона. http://www.codeproject.com/KB/aspnet/ModalDialogV2.aspx

Ответ 5

Для сообщения загрузки я использовал бы <div> с position:absolute, поместите его, используя left и top, и установите для дисплея значение none.

Если вы хотите показать индикатор загрузки, вам придется использовать таймаут div, пока он не будет отображаться. Итак, вы должны изменить свой код на это:

function showLoadingIncidator()
{
    // Display div by setting display to 'inline'

   setTimeout(CalculateAmountOnClick,0);
}

function CalculateAmountOnClick()
{
  // MY time consuming loop!
    {

    }

  // Remove transparent div 
}

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