Я использую jQuery Mobile, и у меня возникают проблемы с пониманием различий между классическим документом и jQuery Mobile.
В чем разница?
Почему
<!-- language: lang-js -->
$(document).ready() {
});
лучше, чем
$(document).on('pageinit') {
});
Каков порядок событий страницы при переходе с одной страницы на другую?
Как я могу отправлять данные с одной страницы на другую и можно ли получить доступ к данным с предыдущей страницы?
Моя оригинальная статья была предназначена для старого способа обработки страниц, в основном все до 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, это порядок разгрузки/загрузки:
страница B - страница события для подтверждения
страница B - событие pagecreate
страница B - event pageitit
страница A - событие pagebeforehide
страница A - событие pageremove
страница A - событие pagehide
страница B - event pagebeforeshow
страница 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 и обратно несколько раз. Существует несколько способов предотвратить эту проблему:
Лучшим решением было бы использовать pageinit
для привязки событий. Если вы посмотрите на официальную документацию, вы обнаружите, что pageinit
будет запускать ТОЛЬКО один раз, точно так же, как документ готов, так что события не будут связаны снова. Это лучшее решение, потому что у вас нет накладных расходов на обработку, например, при удалении событий с помощью метода off.
Рабочий пример jsFiddle: http://jsfiddle.net/Gajotres/AAFH8/
Это рабочее решение сделано на основе предыдущего проблемного примера.
Удалите событие, прежде чем связывать его:
$(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/
Используйте селектор фильтра 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.
Новый, возможно, самый легкий из всех.
$(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&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. Он, как правило, предоставляет вам необходимую информацию, и в отличие от какой-либо другой документации это довольно хорошо, с достаточным количеством объяснений и примеров кода.
$().live()
устарела в jQuery 1.7 и удалена в 1.9, поэтому она действительно должна быть частью любого решения jQuery Mobile. Текущая минимальная версия ядра для JQM 1.7.
Некоторые из вас могут найти это полезным. Просто скопируйте его на свою страницу, и вы получите последовательность, в которой события запускаются в консоли 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");});
И вы увидите, что я имею в виду.
Это правильный способ:
Чтобы выполнить код, который будет доступен только на индексной странице, мы могли бы использовать этот синтаксис:
$(document).on('pageinit', "#index", function() {
...
});
Простая разница между готовым документом и событием страницы в 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() {
});
Пока вы используете .on(), это в основном живой запрос, который вы используете.
С другой стороны,.ready(как в вашем случае) является статическим запросом. При его использовании вы можете динамически обновлять данные и не дожидаться загрузки страницы. Вы можете просто передать значения в свою базу данных (если требуется), когда вводится определенное значение.
Использование живых запросов распространено в тех формах, где мы вводим данные (учетные записи или сообщения или даже комментарии).