Jquery.show() и .hide() не работают в сафари - добавление spinner к <a href

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

Контейнеры загрузки и содержимого находятся в моем базовом шаблоне.


//header

<a href="{{ url_for('welcome', id=id, profile=profile) }}" onclick="spinner();" class="home">Home</a>

//more html

<div id="loading">
    <img src="/static/images/Loading.gif" class="ajax-loader">
</div>

<div id="content">

    {% block content %}{% endblock %}

</div>

<script type="text/javascript">
    function spinner() {
        console.log('fire');
        $("#loading").show();
        $("#content").hide();
    }
</script>

div#loading {
    height: 350px;
    position: relative;
    display: none;
    background: white;
}

.ajax-loader {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    max-width: 100px;
    margin: auto;
}

Мой код отлично работает в firefox и chrome, но не в сафари или на ios.

пс. Я проверил, что моя функция работает, консоль показывает "огонь", который я печатаю сразу после onclick().

Edit

Это единственная ошибка в консоли:

[Error] Failed to load resource: the server responded with a status of 404 (NOT FOUND) (jquery-ui.min.css, line 0)

Обновление 1

Я добавил класс в мой <a href="url" class="..." и обновил свой javascript до следующего:

<script type="text/javascript">
    $(function() {
        $( ".spin_click" ).click(function( event ) {
            event.preventDefault();
            console.log('hiding content');
            $(".content").hide();
            console.log('show spinner');
            $(".se-pre-con").show();
            console.log('waiting now...');
        });
    });
</script>

#html

<div class="se-pre-con"></div>
    <div class="content">

        {% block content %}{% endblock %}
    </div>

Я могу получить сафари, чтобы показать div se-pre-con, когда я нажимаю ссылку, однако полностью отключает ссылку href. Можно ли продолжить ссылку, выполнив команду .show() в jquery? Возможно, я неправильно понял preventDefault();, но я подумал, что он может действовать как обходной путь. Проблема все еще существует только в Safari

Обновление 2

Как было предложено @maximast, я решил использовать addClass и removeClass. Как обычно, он работает в chrome и firefox, но не в сафари. Код тот же, я только что добавил класс hide, который добавляется и удаляется по мере необходимости.

Если я использую сафари-инспектор и удаляю класс hide вручную, , счетчик будет отображаться. Когда я нажимаю на ссылку на странице, чтобы вызвать функцию jquery, я вижу, что класс hide удален правильно из div. Однако, даже если класс hide удален, счетчик не появляется. Возможно, я упускаю здесь что-то очевидное.

Вот библиотеки, которые я использую:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.0/moment.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.2/Chart.min.js"></script>

Обновление 3

Вот ссылка на тестовую страницу. Существует ссылка, которая заставляет приложение спать в течение 3 секунд, предоставляя достаточно времени для запуска счетчика. Spinner сидит в логотипе. На тестовой странице будет показан счетчик, работающий в Chrome и Firefox, но не сафари. Реализация с помощью этой кнопки точно такая же, как и в других местах моего приложения.

http://ec2-54-88-245-245.compute-1.amazonaws.com/spinner-test

Я изменил ссылку в логотипе на: <a href='#', который в первый раз отображает счетчик во всех трех браузерах. (прогресс!). Однако, когда вы нажимаете кнопку "Click to trigger spinner". link, происходит следующее:

  • Chrome - spinner работает в первый раз.
  • Firefox - spinner работает в первый раз, однако было несколько случаев, когда я должен был щелкнуть его второй раз.
  • Safari - не повезло.

Вот флеш-код с управлением страницей тестовой страницы:

@app.route('/spinner-test', methods=['GET'])
def spinner():
    return render_template('spinner-test.html')


@app.route('/wait', methods=['GET'])
def wait():
    time.sleep(3)
    return redirect(url_for('spinner'))

Ответ 1

Кажется, что ваша функция называется spinner, но вы пытаетесь запустить loading() внутри своего тега a (onclick="javascript:loading();). Изменение имени вашей функции на loading должно быть исправлено.

Вот рабочий пример:

https://jsfiddle.net/nvzge1e8/5/

Изменить для обновленного вопроса:

Вам нужно предотвратить событие, если вы вставляете event.preventDefault() в начало вашей функции, он должен воспроизводить анимацию. Помните, что это приведет к тому, что ваша ссылка не будет фактически отправлена ​​на страницу, поэтому вам может потребоваться добавить перенаправленную по времени на любую страницу, на которую вы их отправляете.

Пример кода:

 $(function() {
 $(".spin_click").click(function(event) {
     event.preventDefault()
     $("#logo_spinner").attr("src", "/static/images/loaders/spinner.gif");
     $('.content').addClass('hide');
     setTimeout(function() {
         window.location.href = "/wait";
     }, 4000);

 });
});

Ответ 2

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

Я предполагаю, что код не предоставлен более сложным, чем вы описываете (или некоторые зависимости отсутствуют).

Поскольку вы уже используете jQuery, я даю вам свой ответ, используя эту библиотеку.

( обновлено: добавлены другие библиотеки, используемые OP, чтобы проверить, присутствует ли их присутствие в описанной проблеме)

См. пример кода ниже:

$(function() {
  // add event listener to home (class) - 
  // used instead of inline binding using 'onclick'
  $('.home').on('click', function() {
    console.log('show spinner');
    // show spinner right away
    $("#loading").show();

    console.log('waiting now...');

    // simulate delay in fetching backend response (delay is 3 secs)
    // contains the callback function to be invoked after your response is completed
    setTimeout(function() {
      // hide spinner
      console.log('hide spinner');
      $("#loading").hide();

      // show content
      console.log('show content');
      $("#content").show();
    }, 3 * 1000); // time is in ms so 1000ms = 1 sec (3*1000=3secs)

  });
});
div#loading {
  height: 50px;
  position: relative;
  display: none;
  background: white;
}
.ajax-loader {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  max-width: 100px;
  margin: auto;
}
#content {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.0/moment.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.2/Chart.min.js"></script>


<header>
  Header here
</header>
<hr/>

<a href="#" class="home">Home</a>

<div id="loading">
  <img class="ajax-loader" src="https://i.stack.imgur.com/akN6H.png?s=48&amp;g=1" alt="" width="24" height="24" class="avatar-me js-avatar-me">
</div>
<hr/>
<div id="content">

  content will be loaded here

</div>

<footer>footer here
</footer>

Ответ 3

Я не тестировал это в Safari, но вы могли попробовать

$("#loading").fadeIn(0);
$("#content").fadeOut(0);

Но не забудьте удалить

display: none

из вашего CSS

Ответ 4

Извините, вы не пытались воспроизвести свою ошибку, но если вы не должны использовать elem.hide() и elem.show().

В качестве альтернативы вы можете работать с функциями addClass и removeClass

$('#loading').addClass('hide');
$('#loading').removeClass('hide');

с .hide { display: none; }

отлично работает на сафари.

Ответ 5

Вместо $('elem').show() и $('elem').hide() попробуйте использовать...

$('elem').attr( 'data-display', 'block');
$('elem').attr( 'data-display', 'none');

В CSS добавить...

Селектор атрибутов, используемый дважды для повышения специфичности;)

[data-display][data-display='none'] {
  display:none!important;
}
[data-display][data-display='block'] {
  display:block!important;
}

Код будет выглядеть так:

$('h1').attr( 'data-display', 'block');
$('h2').attr( 'data-display', 'none');
[data-display][data-display='none'] {
  display:none!important;
}
[data-display][data-display='block'] {
  display:block!important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>I'm displayed</h1>
<h2>I'm hidden</h2>
<p>
  I'm unaffected ;)
</p>

Ответ 6

У меня та же проблема, что и у OP, я просто пытаюсь отображать элемент только тогда, когда в IOS не работают show/hide, либо не работает любая комбинация add class/remove class.

В моем случае я работаю над прогрессивным веб-приложением, и этот вопрос съел половину моего дня.

У меня даже есть предупреждение в том же методе функции, который пытается запустить шоу и/или удалить класс. Это предупреждение срабатывает, как и ожидалось, но элемент никогда не появляется. Если я просто удаляю класс скрытия и перезагружаю страницу, она появляется, если я изменяю элемент для отображения по умолчанию в CSS, он работает, но ничего из того, что я до сих пор пробовал, заставляет элемент появляться через JS. Я пробовал это в электронной таблице CSS и с помощью встроенного стиля. Я пытался использовать видимость, не показывать/блокировать, и просто скрывать/показывать через JS. Ничто не работает на IOS. Прекрасно работает в Chrome, Internet Explorer, Edge, Firefox и других браузерах. Это просто не будет работать в Safari на IOS, и, честно говоря, я озадачен, почему.

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

!!ОБНОВИТЬ!!

Исправлено это да! После большого стресса коллега предположил, что это может быть блокировщик всплывающих окон в Safari... он предложил привязать его к щелчку, чтобы подтвердить концепцию.

В этот конкретный момент появилась модальная ошибка, которая заставила меня задуматься... подожди минутку - как это работает. Это не происходит при загрузке страницы! Есть задержка!

И VOILA - упаковка функции шоу в очень маленькую функцию setTimeout (10 мс) решает проблему.

В моем случае я добавляю функциональность для репликации функциональности Android PWA "добавить на домашний экран" для IOS, поэтому, когда устройство определяется как IOS и когда PWA еще не находится на домашнем экране, пользователю осторожно предлагается добавить его,

Если кто-то еще достигнет этого по той же причине, пожалуйста.

:)