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

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

function CalculateAmountOnClick() {
  // Display transparent div

  // MY time consuming loop!
    {

    }

  // Remove transparent div 

}

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

ТИА

Ответы [ 5 ]

11 голосов
/ 15 октября 2008

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
});
5 голосов
/ 17 октября 2008

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

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

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

2 голосов
/ 15 октября 2008

Я бы сделал что-то вроде:

  1. Показать div (display:inline)
  2. сделать position:absolute
  3. дайте ему z-index:99
  4. высота и ширина 100%
  5. когда обработка завершена, установите display:none

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

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

0 голосов
/ 15 октября 2008

Для сообщения о загрузке я бы использовал <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 
}

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

0 голосов
/ 15 октября 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...