JQuery Mobile: документ готов против событий страницы

238

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

  • В чем разница?

    Почему

    <!-- language: lang-js -->
    
    $(document).ready() {
    
    });
    

    лучше, чем

    $(document).on('pageinit') {
    
    });
    
  • Каков порядок событий страницы при переходе с одной страницы на другую?

  • Как я могу отправлять данные с одной страницы на другую и можно ли получить доступ к данным с предыдущей страницы?

  • 0
    По вопросу 1 они оба одинаковы. Можете ли вы изменить это или объяснить немного больше, что вы имеете в виду?
  • 0
    Извините моя ошибка.
Показать ещё 1 комментарий
Теги:
cordova
jquery-mobile

5 ответов

456
Лучший ответ

Обновление jQuery Mobile 1.4:

Моя оригинальная статья была предназначена для старого способа обработки страниц, в основном все до jQuery Mobile 1.4. Старый способ обработки теперь устарел, и он останется активным до (включая) jQuery Mobile 1.5, поэтому вы можете использовать все, упомянутое ниже, по крайней мере до следующего года и jQuery Mobile 1.6.

Старые события, в том числе pageinit, больше не существуют, они заменяются виджетами pagecontainer. Pageinit полностью удаляется, и вместо этого вы можете использовать pagecreate, это событие оставалось неизменным и не изменилось.

Если вы заинтересованы в новом способе обработки событий страницы, посмотрите здесь, в любом другом случае не стесняйтесь продолжать эту статью. Вы должны прочитать этот ответ, даже если вы используете jQuery Mobile 1.4 +, он выходит за рамки событий страницы, поэтому вы, вероятно, найдете много полезной информации.

Старое содержание:

Эта статья также может быть найдена как часть моего блога ЗДЕСЬ.

$(document).on('pageinit') vs $(document).ready()

Первое, что вы узнали в jQuery, - это вызвать код внутри функции $(document).ready() чтобы все выполнялось сразу после загрузки DOM. Однако в jQuery Mobile Ajax используется для загрузки содержимого каждой страницы в DOM при навигации. Из-за этого $(document).ready() будет запускаться до того, как будет загружена ваша первая страница, и каждый код, предназначенный для обработки страниц, будет выполнен после обновления страницы. Это может быть очень тонкая ошибка. На некоторых системах может показаться, что он работает нормально, но на других он может вызвать неустойчивость, трудно повторить странность.

Классический синтаксис jQuery:

$(document).ready(function() {

});

Чтобы решить эту проблему (и доверять мне, что это проблема), разработчики jQuery Mobile создали события страницы. В двух словах страницы события - события, инициированные в определенной точке исполнения страницы. Одним из этих событий страницы является событие pageinit, и мы можем использовать его следующим образом:

$(document).on('pageinit', function() {

});

Мы можем пойти еще дальше и использовать идентификатор страницы вместо селектора документов. Скажем, у нас есть страница jQuery Mobile с индексом id:

<div data-role="page" id="index">
    <div data-theme="a" data-role="header">
        <h3>
            First Page
        </h3>
        <a href="#second" class="ui-btn-right">Next</a>
    </div>

    <div data-role="content">
        <a href="#" data-role="button" id="test-button">Test button</a>
    </div>

    <div data-theme="a" data-role="footer" data-position="fixed">

    </div>
</div>

Чтобы выполнить код, доступный только на индексной странице, мы могли бы использовать этот синтаксис:

$('#index').on('pageinit', function() {

});

Событие Pageinit будет выполняться каждый раз, когда страница будет загружена и показана в первый раз. Он не будет запускаться снова, если страница не обновляется вручную или загрузка страницы Ajax не отключена. Если вы хотите, чтобы код выполнялся каждый раз, когда вы посещаете страницу, лучше использовать событие pagebeforeshow.

Здесь приведен рабочий пример: http://jsfiddle.net/Gajotres/Q3Usv/, чтобы продемонстрировать эту проблему.

Еще несколько заметок по этому вопросу. Независимо от того, используете ли вы 1 html несколько страниц или несколько парадигм HTML файлов, рекомендуется отделить все ваши пользовательские JavaScript-страницы в одном отдельном файле JavaScript. Это позволит сделать код лучше, но у вас будет гораздо лучший обзор кода, особенно при создании приложения jQuery Mobile.

Там также есть еще одно специальное событие jQuery Mobile, которое называется mobileinit. Когда jQuery Mobile запускается, он запускает событие mobileinit для объекта документа. Чтобы переопределить настройки по умолчанию, привяжите их к mobileinit. Одним из хороших примеров использования mobileinit является отключение загрузки страницы Ajax или изменение поведения загрузчика по умолчанию Ajax.

$(document).on("mobileinit", function(){
  //apply overrides here
});

Планирование событий на странице событий

Сначала все события можно найти здесь: http://api.jquerymobile.com/category/events/

Допустим, у нас есть страница A и страница B, это порядок разгрузки/загрузки:

  1. страница B - страница события для подтверждения

  2. страница B - событие pagecreate

  3. страница B - event pageitit

  4. страница A - событие pagebeforehide

  5. страница A - событие pageremove

  6. страница A - событие pagehide

  7. страница B - event pagebeforeshow

  8. страница B - событие pageshow

Для лучшего понимания событий на страницах прочтите следующее:

  • pagebeforeload, pageload и pageloadfailed при загрузке внешней страницы
  • pagebeforechange, pagechange и pagechangefailed - события изменения страницы. Эти события запускаются, когда пользователь перемещается между страницами в приложениях.
  • pagebeforeshow, pagebeforehide, pageshow и pagehide - события перехода страницы. Эти события запускаются до, во время и после перехода и называются.
  • pagebeforecreate, pagecreate и pageinit предназначены для инициализации страницы.
  • pageremove может быть запущен, а затем обработан, когда страница удалена из DOM

Загрузка страницы Пример jsFiddle: http://jsfiddle.net/Gajotres/QGnft/

Если AJAX не включен, некоторые события могут не срабатывать.

Предотвращение перехода страницы

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

$(document).on('pagebeforechange', function(e, data){
    var to = data.toPage,
        from = data.options.fromPage;

    if (typeof to  === 'string') {
        var u = $.mobile.path.parseUrl(to);
        to = u.hash || '#' + u.pathname.substring(1);
        if (from) from = '#' + from.attr('id');

        if (from === '#index' && to === '#second') {
            alert('Can not transition from #index to #second!');
            e.preventDefault();
            e.stopPropagation();

            // remove active status on a button, if transition was triggered with a button
            $.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active ui-focus ui-btn');;
        }
    }
});

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

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

Предотвращение связывания/запуска нескольких событий

jQuery Mobile работает по-другому, чем классические веб-приложения. В зависимости от того, как вы смогли привязать свои события каждый раз, когда вы посещаете какую-либо страницу, он будет связывать события снова и снова. Это не ошибка, а просто как jQuery Mobile обрабатывает свои страницы. Например, взгляните на этот фрагмент кода:

$(document).on('pagebeforeshow','#index' ,function(e,data){
    $(document).on('click', '#test-button',function(e) {
        alert('Button click');
    });
});

Рабочий пример jsFiddle: http://jsfiddle.net/Gajotres/CCfL4/

Каждый раз, когда вы посещаете страницу #index, событие click будет привязано к кнопке # test-button. Проверьте его, переместившись со страницы 1 на страницу 2 и обратно несколько раз. Существует несколько способов предотвратить эту проблему:

Решение 1

Лучшим решением было бы использовать pageinit для привязки событий. Если вы посмотрите на официальную документацию, вы обнаружите, что pageinit будет запускать ТОЛЬКО один раз, точно так же, как документ готов, так что события не будут связаны снова. Это лучшее решение, потому что у вас нет накладных расходов на обработку, например, при удалении событий с помощью метода off.

Рабочий пример jsFiddle: http://jsfiddle.net/Gajotres/AAFH8/

Это рабочее решение сделано на основе предыдущего проблемного примера.

Решение 2

Удалите событие, прежде чем связывать его:

$(document).on('pagebeforeshow', '#index', function(){
    $(document).off('click', '#test-button').on('click', '#test-button',function(e) {
        alert('Button click');
    });
});

Рабочий пример jsFiddle: http://jsfiddle.net/Gajotres/K8YmG/

Решение 3

Используйте селектор фильтра jQuery, например:

$('#carousel div:Event(!click)').each(function(){
    //If click is not bind to #carousel div do something
});

Поскольку фильтр событий не является частью официальной структуры jQuery, его можно найти здесь: http://www.codenothing.com/archives/2009/event-filter/

В двух словах, если скорость является вашей главной проблемой, решение 2 намного лучше, чем решение 1.

Решение 4

Новый, возможно, самый легкий из всех.

$(document).on('pagebeforeshow', '#index', function(){
    $(document).on('click', '#test-button',function(e) {
        if(e.handled !== true) // This will prevent event triggering more than once
        {
            alert('Clicked');
            e.handled = true;
        }
    });
});

Рабочий пример jsFiddle: http://jsfiddle.net/Gajotres/Yerv9/

Tnx для sholsinger для этого решения: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

pageChange события quirks - запуск дважды

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

Причина, по которой событие pagebeforechange происходит дважды, связана с рекурсивным вызовом в changePage, когда toPage не является объектом DOM с расширенным jQuery. Эта рекурсия опасна, так как разработчику разрешено изменять значение toPage внутри события. Если разработчик последовательно устанавливает toPage в строку, внутри обработчика события pagebeforechange, независимо от того, был ли он объектом, возникает бесконечный рекурсивный цикл. Событие pageload передает новую страницу как свойство страницы объекта данных (это должно быть добавлено в документацию, она не указана в настоящее время). Поэтому событие pageload можно использовать для доступа к загруженной странице.

В нескольких словах это происходит потому, что вы отправляете дополнительные параметры через pageChange.

Пример:

<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&amp;name=Sat"><h3>Sat</h3></a>

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

Время изменения страницы

Как уже упоминалось, при переходе с одной страницы jQuery Mobile на другую, как правило, либо путем перехода по ссылке на другую страницу jQuery Mobile, которая уже существует в DOM, либо путем ручного вызова $.mobile.changePage, происходят несколько событий и последующие действия. На высоком уровне происходят следующие действия:

  • Начался процесс изменения страницы
  • Загружается новая страница
  • Содержимое этой страницы "расширено" (в стиле)
  • Переход (слайд/поп/и т.д.) С существующей страницы на новую страницу происходит

Это средний показатель перехода по страницам:

Загрузка и обработка страницы: 3 мс

Увеличение страницы: 45 мс

Переход: 604 мс

Общее время: 670 мс

* Эти значения указаны в миллисекундах.

Таким образом, вы можете видеть, что переходное событие составляет почти 90% времени выполнения.

Обработка данных/параметров между переходами страниц

При переходе страницы можно отправить параметр /s с одной страницы на другую. Это можно сделать несколькими способами.

Ссылка: https://stackoverflow.com/questions/13928193/cordovajquery-value-sent-to-another-static-html-page

Решение 1:

Вы можете передавать значения с помощью переменнойPage:

$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });

И читайте их так:

$(document).on('pagebeforeshow', "#index", function (event, data) {
    var parameters = $(this).data("url").split("?")[1];;
    parameter = parameters.replace("parameter=","");
    alert(parameter);
});

Пример:

index.html

<!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>
    </title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
    <script>
        $(document).on('pagebeforeshow', "#index",function () {
            $(document).on('click', "#changePage",function () {
                $.mobile.changePage('second.html', { dataUrl : "second.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : false, changeHash : true });
            });
        });

        $(document).on('pagebeforeshow', "#second",function () {
            var parameters = $(this).data("url").split("?")[1];;
            parameter = parameters.replace("parameter=","");
            alert(parameter);
        });
    </script>
   </head>
   <body>
    <!-- Home -->
    <div data-role="page" id="index">
        <div data-role="header">
            <h3>
                First Page
            </h3>
        </div>
        <div data-role="content">
          <a data-role="button" id="changePage">Test</a>
        </div> <!--content-->
    </div><!--page-->

  </body>
</html>

second.html

<!DOCTYPE html>
  <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>
    </title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
   </head>
   <body>
    <!-- Home -->
    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Second Page
            </h3>
        </div>
        <div data-role="content">

        </div> <!--content-->
    </div><!--page-->

  </body>
</html>

Решение 2:

Или вы можете создать постоянный объект JavaScript для целей хранения. До тех пор, пока Ajax используется для загрузки страницы (и страница не перезагружается каким-либо образом), этот объект останется активным.

var storeObject = {
    firstname : '',
    lastname : ''
}

Пример: http://jsfiddle.net/Gajotres/9KKbx/

Решение 3:

Вы также можете получить доступ к данным с предыдущей страницы следующим образом:

$(document).on('pagebeforeshow', '#index',function (e, data) {
    alert(data.prevPage.attr('id'));
});

Объект prevPage содержит полную предыдущую страницу.

Решение 4:

В качестве последнего решения у нас есть отличная реализация HTML localStorage. Он работает только с браузерами HTML5 (включая браузеры Android и iOS), но все сохраненные данные сохраняются при обновлении страницы.

if(typeof(Storage)!=="undefined") {
    localStorage.firstname="Dragan";
    localStorage.lastname="Gaic";
}

Пример: http://jsfiddle.net/Gajotres/J9NTr/

Наверное, лучшее решение, но в некоторых версиях iOS 5.X. Это хорошо известная ошибка.

Не использовать .live()/.bind()/.delegate()

Я забыл упомянуть (и tnx andleer для напоминания мне) использовать вкл/выкл для привязки/отмены привязки событий, live/die и bind/unbind устарели.

Метод.live() jQuery рассматривался как находка, когда он был введен в API в версии 1.3. В типичном приложении jQuery может быть много манипуляций с DOM, и может стать очень утомительным, чтобы зацепить и отцепить, когда элементы приходят и уходят. Метод .live() позволил подключить событие к жизни приложения на основе его селектора. Отлично? Неправильно, метод .live() очень медленный. Метод .live() фактически перехватывает события в объект документа, что означает, что событие должно пузыриться из элемента, который сгенерировал событие, пока не достигнет документа. Это может быть поразительно трудоемким.

Теперь он устарел. Люди в команде jQuery больше не рекомендуют использовать его, и я тоже. Даже несмотря на то, что может быть утомительно перехватывать и отцеплять события, ваш код будет намного быстрее без .live() чем с ним.

Вместо .live() вы должны использовать .on(). .on() примерно в 2-3 раза быстрее, чем .live(). Взгляните на этот показатель привязки к событию: http://jsperf.com/jquery-live-vs-delegate-vs-on/34, оттуда будет ясно.

Сравнительный анализ:

Там отличный сценарий, выполненный для бенчмаркинга событий в мобильных приложениях jQuery. Его можно найти здесь: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js. Но прежде чем сделать что - нибудь с этим я советую вам, чтобы удалить его alert системы оповещения (каждая "страница изменения" собирается показать вам эти данные, останавливая приложение) и изменить его на console.log функцию.

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

Итоговые заметки

Всегда, и я имею в виду всегда читать официальную документацию jQuery Mobile. Он, как правило, предоставляет вам необходимую информацию, и в отличие от какой-либо другой документации это довольно хорошо, с достаточным количеством объяснений и примеров кода.

Изменения:

  • 30.01.2013 - Добавлен новый метод предотвращения множественных событий
  • 31.01.2013 - Добавлено лучшее разъяснение для раздела Управление данными/параметрами между переходами страниц
  • 03.02.2013 - Добавлен новый контент/примеры к главе Управление данными/параметрами между переходами страниц
  • 22.05.2013 - добавлено решение для предотвращения перехода страницы/изменения и добавлено ссылки на официальную документацию API
  • 18.05.2013 - добавлено другое решение против множественного связывания событий
  • 2
    $().live() устарела в jQuery 1.7 и удалена в 1.9, поэтому она действительно должна быть частью любого решения jQuery Mobile. Текущая минимальная версия ядра для JQM 1.7.
  • 16
    +1 очень полезная сводка критического поведения при загрузке страниц
Показать ещё 5 комментариев
17

Некоторые из вас могут найти это полезным. Просто скопируйте его на свою страницу, и вы получите последовательность, в которой события запускаются в консоли Chrome (Ctrl + Shift + I).

$(document).on('pagebeforecreate',function(){console.log('pagebeforecreate');});
$(document).on('pagecreate',function(){console.log('pagecreate');});
$(document).on('pageinit',function(){console.log('pageinit');});
$(document).on('pagebeforehide',function(){console.log('pagebeforehide');});
$(document).on('pagebeforeshow',function(){console.log('pagebeforeshow');});
$(document).on('pageremove',function(){console.log('pageremove');});
$(document).on('pageshow',function(){console.log('pageshow');});
$(document).on('pagehide',function(){console.log('pagehide');});
$(window).load(function () {console.log("window loaded");});
$(window).unload(function () {console.log("window unloaded");});
$(function () {console.log('document ready');});

Вы не увидите разгрузите консоль, поскольку она запускается, когда страница выгружается (когда вы удаляетесь от страницы). Используйте его так:

$(window).unload(function () { debugger; console.log("window unloaded");});

И вы увидите, что я имею в виду.

3

Это правильный способ:

Чтобы выполнить код, который будет доступен только на индексной странице, мы могли бы использовать этот синтаксис:

$(document).on('pageinit', "#index",  function() {
    ...
});
  • 10
    ответ выше говорит о том же, не так ли? :)
1

Простая разница между готовым документом и событием страницы в jQuery-mobile заключается в следующем:

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

    $(document).ready(function(e) {
        // Your code
    });
    
  • Когда есть событие страницы, используйте для обработки определенного события страницы:

    <div data-role="page" id="second">
        <div data-role="header">
            <h3>
                Page header
            </h3>
        </div>
        <div data-role="content">
            Page content
        </div> <!--content-->
        <div data-role="footer">
            Page footer
        </div> <!--footer-->
    </div><!--page-->
    

Вы также можете использовать документ для обработки события pageinit:

$(document).on('pageinit', "#mypage", function() {

});
-1

Пока вы используете .on(), это в основном живой запрос, который вы используете.

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню