jquery addClass не вступает в силу немедленно - PullRequest
1 голос
/ 02 ноября 2019

У меня есть страница, которая загружает данные (она будет использовать AJAX), поэтому я хочу отобразить сообщение «Идет загрузка, подождите». Сейчас я имитирую задержку в сети с помощью петли. Я использую JQuery для установки и отображения сообщения, но оно не отображается до тех пор, пока цикл не завершится. Что мне нужно сделать, чтобы "очистить" команды JQuery, чтобы сообщение отображалось до вызова цикла?

Я предоставил скелетные CSS, HTML и JQuery / JavaScript ниже.

<!DOCTYPE html>
<html>
<head>
<style>
.ais-card-message {
    padding: 6px;
    margin-top: 6px;
    margin-bottom: 6px;
    text-align: left;
}
.ais-card-message-info {
    background-color: lightskyblue;
}
.ais-card-message-warn {
    background-color: lightpink;
}
</style>
</head>
<body>
    <div id="title">
        <p>Message "Loading, please wait ..." should appear below when button clicked.&nbsp;
        Followed by either "Error" or "Loaded" after a short delay.</p>
    </div>
    <div id="data">Data will be loaded here</div>
    <div id="msgBox" class="ais-card-message">Messages should display here</div>
    <div><button id="btnLoad">Load</button></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
    $(document).ready(function(){
        function showMsg(msg, type) {
            // msg is message to display. type is either "info" or "warn"
            $('#msgBox').removeClass("ais-card-message-info ais-card-message-warn");
            $('#msgBox').addClass("ais-card-message-" + type);
            $('#msgBox').text(msg);
            $('#msgBox').show();
            return
        }
        $('#btnLoad').click(function(){
            // For some reason the following message doesn't display
            showMsg('Loading, please wait ...', 'info');
            if (!loadData()) {
                // But this message does display if loadData returns false
                showMsg('Error', 'warn');
                return
            }else{
                // and this message also displays if loadData returns true
                showMsg('Loaded', 'info');
                return
            }
        });
        function loadData() {
            // Just a loop to simulate network delay
            var i;
            for (i=0; i < 100000; i++) {
                var j;
                for (j=0; j < 100000; j++) {
                    var k = Math.sqrt(j);
                }
            }
            $('#data').text("Here is some dummy data");
            return true
        }
    });
</script>    
</body>
</html>

1 Ответ

1 голос
/ 02 ноября 2019

У вас есть пара проблем в вашем коде. Во-первых, в своем «ложном» AJAX-запросе вы используете цикл. Это синхронная операция и причина проблемы, препятствующей обновлению пользовательского интерфейса;цикл останавливает выполнение любой другой операции (т. е. обновление элемента в DOM). Следовательно, он обновляется только после завершения цикла.

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

Для этого вам нужно вернуть обещание из $.ajax() в функции loadData(). Затем вы можете использовать методы done() и fail() для обновления DOM на основе результата запроса. Это должно выглядеть примерно так:

$('#btnLoad').click(function() {
  showMsg('Loading, please wait ...', 'info');
  loadData().done(function() {
   showMsg('Loaded', 'info');
  }).fail(function() {
    showMsg('Error', 'warn');
  });
});

function loadData() {
  return $.ajax({
    url: '/yourpage',
    data: {
      foo: 'bar'
    }
  });
} 

Ниже приведен рабочий пример, в котором смоделирован запрос AJAX путем ручного разрешения отложенного объекта через 3 секунды. Вы можете видеть, что сообщение о загрузке теперь отображается правильно из-за исправленного использования асинхронной логики.

$(document).ready(function() {
  function showMsg(msg, type) {
    $('#msgBox')
      .removeClass("ais-card-message-info ais-card-message-warn")
      .addClass("ais-card-message-" + type)
      .text(msg)
      .show();
  }
  
  $('#btnLoad').click(function() {
    showMsg('Loading, please wait ...', 'info');
    loadData().done(function() {
      showMsg('Loaded', 'info');
    }).fail(function() {
      showMsg('Error', 'warn');
    });
  });

  function loadData() {
    // mock AJAX request, just for this demo
    var deferred = jQuery.Deferred();
    setTimeout(function() {
      deferred.resolve();
    }, 3000);
    return deferred;
  }
});
.ais-card-message {
  padding: 6px;
  margin-top: 6px;
  margin-bottom: 6px;
  text-align: left;
}

.ais-card-message-info {
  background-color: lightskyblue;
}

.ais-card-message-warn {
  background-color: lightpink;
}
<div id="title">
  <p>Message "Loading, please wait ..." should appear below when button clicked.&nbsp; Followed by either "Error" or "Loaded" after a short delay.</p>
</div>
<div id="data">Data will be loaded here</div>
<div id="msgBox" class="ais-card-message">Messages should display here</div>
<div><button id="btnLoad">Load</button></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...