Оновлення 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')
проти $(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. Якщо ви хочете, щоб код виконувався щоразу, коли ви відвідуєте сторінку, краще скористатися сторінкою шоу.
Ось робочий приклад: http://jsfiddle.net/Gajotres/Q3Usv/, щоб продемонструвати цю проблему.
Трохи більше приміток до цього питання. Незалежно від того, якщо ви використовуєте 1 html кілька сторінок або парадигму декількох файлів HTML, радимо розділити всі ваші користувацькі сторінки обробки JavaScript в один окремий файл JavaScript. Це помітить, що полегшить ваш код, але у вас буде набагато кращий огляд коду, особливо під час створення програми jQuery Mobile .
Також є ще одна спеціальна подія jQuery Mobile, і вона називається mobileinit . Коли jQuery Mobile запускається, він запускає подію mobileinit на об'єкті документа. Щоб змінити налаштування за замовчуванням, прив’яжіть їх до mobileinit . Одним із хороших прикладів використання мобільних пристроїв є вимкнення завантаження сторінки Ajax або зміна поведінки завантажувача Ajax за замовчуванням.
$(document).on("mobileinit", function(){
//apply overrides here
});
Порядок переходу подій на сторінці
По-перше, всі події можна знайти тут: http://api.jquerymobile.com/category/events/
Скажімо, у нас є сторінка A і сторінка B, це порядок вивантаження / завантаження:
сторінка B - сторінка подій, попередньо створити
сторінка B - подія pagecreate
сторінка B - подія pageinit
сторінка A - сторінка подій перед головою
сторінка A - усунення сторінки події
сторінка A - подія pagehide
сторінка B - сторінка події перед попереднім шоу
сторінка B - покази сторінок
Для кращого розуміння подій сторінки читайте це:
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, подія натискання буде прив’язана до кнопки # тестова кнопка . Перевірте це, переміщаючи з сторінки 1 на сторінку 2 і назад кілька разів. Є кілька способів запобігти цій проблемі:
Рішення 1
Найкращим рішенням буде використання pageinit
прив'язки подій. Якщо ви подивитесь на офіційну документацію, то виявите, що вона pageinit
буде запущена ТІЛЬКИ один раз, як і готовий документ, тому немає жодного способу, щоб події не були пов'язані знову. Це найкраще рішення, оскільки у вас немає обробки накладних витрат, як при видаленні подій методом вимкнення.
Приклад роботи 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/
pageЗмінити вигадки події - запускається двічі
Іноді подія зміни сторінки може викликати двічі, і це не має нічого спільного з проблемою, згаданою раніше.
Причина того, що подія pagebeforechange відбувається двічі, пов’язана з рекурсивним викликом в changePage, коли toPage не є об'єктом DOM, розширеним jQuery. Ця рекурсія небезпечна, оскільки розробник може змінити точку сторінки в рамках події. Якщо розробник послідовно встановлює toPage на рядок, всередині сторінки обробляти події pagebechange, незалежно від того, був це об'єктом чи ні, не призведе до нескінченного рекурсивного циклу. Подія завантаження сторінки передає нову сторінку як властивість сторінки об’єкта даних (Це слід додати до документації, вона наразі не вказана). Тому подія завантаження сторінки може бути використана для доступу до завантаженої сторінки.
У кількох словах це відбувається, тому що ви надсилаєте додаткові параметри через 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% часу виконання.
Маніпулювання даними / параметрами між переходами сторінки
Під час переходу сторінки можна надсилати параметр / с з однієї сторінки на іншу. Це можна зробити декількома способами.
Довідка: https://stackoverflow.com/a/13932240/1848600
Рішення 1:
Ви можете передавати значення за допомогою changePage:
$.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 Mobile . Його можна знайти тут: 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 - Додано ще одне рішення проти прив'язки до кількох подій