Cập nhật jQuery Mobile 1.4:
Bài viết gốc của tôi được dành cho cách xử lý trang cũ, về cơ bản là mọi thứ trước jQuery Mobile 1.4. Cách xử lý cũ hiện không được chấp nhận và nó sẽ duy trì hoạt động cho đến khi (bao gồm) jQuery Mobile 1.5, vì vậy bạn vẫn có thể sử dụng mọi thứ được đề cập bên dưới, ít nhất là cho đến năm sau và jQuery Mobile 1.6.
Các sự kiện cũ, bao gồm pageinit không còn tồn tại nữa, chúng được thay thế bằng widget pagecontainer . Pageinit bị xóa hoàn toàn và thay vào đó bạn có thể sử dụng pagecreate , sự kiện đó vẫn giữ nguyên và nó sẽ không bị thay đổi.
Nếu bạn quan tâm đến cách xử lý sự kiện trang mới, hãy xem ở đây , trong mọi trường hợp khác, vui lòng tiếp tục với bài viết này. Bạn nên đọc câu trả lời này ngay cả khi bạn đang sử dụng jQuery Mobile 1.4 +, nó vượt xa các sự kiện của trang để có thể bạn sẽ tìm thấy nhiều thông tin hữu ích.
Nội dung cũ hơn:
Bài viết này cũng có thể được tìm thấy như một phần của blog của tôi TẠI ĐÂY .
$(document).on('pageinit')
đấu với $(document).ready()
Điều đầu tiên bạn học trong jQuery là gọi mã bên trong $(document).ready()
hàm để mọi thứ sẽ thực thi ngay khi DOM được tải. Tuy nhiên, trong jQuery Mobile , Ajax được sử dụng để tải nội dung của từng trang vào DOM khi bạn điều hướng. Bởi vì điều này $(document).ready()
sẽ kích hoạt trước khi trang đầu tiên của bạn được tải và mọi mã dành cho thao tác trang sẽ được thực hiện sau khi làm mới trang. Đây có thể là một lỗi rất tinh tế. Trên một số hệ thống có vẻ như nó hoạt động tốt, nhưng trên các hệ thống khác, nó có thể gây ra sự kỳ lạ, khó lặp lại sự kỳ lạ xảy ra.
Cú pháp jQuery cổ điển:
$(document).ready(function() {
});
Để giải quyết vấn đề này (và tin tôi đi, đây là một vấn đề) Các nhà phát triển jQuery Mobile đã tạo các sự kiện trang. Trong một sự kiện trang tóm tắt là các sự kiện được kích hoạt trong một điểm cụ thể của việc thực hiện trang. Một trong những sự kiện trang đó là một sự kiện pageinit và chúng ta có thể sử dụng nó như thế này:
$(document).on('pageinit', function() {
});
Chúng ta có thể đi xa hơn và sử dụng id trang thay vì bộ chọn tài liệu. Giả sử chúng ta có trang jQuery Mobile với chỉ mục 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>
Để thực thi mã sẽ chỉ có sẵn cho trang chỉ mục, chúng tôi có thể sử dụng cú pháp này:
$('#index').on('pageinit', function() {
});
Sự kiện Pageinit sẽ được thực hiện mỗi khi trang sắp được tải và hiển thị lần đầu tiên. Nó sẽ không kích hoạt lại trừ khi trang được làm mới thủ công hoặc tải trang Ajax bị tắt. Trong trường hợp bạn muốn mã thực thi mỗi khi bạn truy cập một trang, tốt hơn là sử dụng sự kiện pagebeforeshow .
Đây là một ví dụ hoạt động: http://jsfiddle.net/Gajotres/Q3Usv/ để chứng minh vấn đề này.
Ít ghi chú hơn về câu hỏi này. Không có vấn đề gì nếu bạn đang sử dụng 1 html nhiều trang hoặc nhiều mô hình tệp HTML, bạn nên tách tất cả các xử lý trang JavaScript tùy chỉnh của bạn thành một tệp JavaScript riêng biệt. Điều này sẽ lưu ý làm cho mã của bạn tốt hơn nhưng bạn sẽ có tổng quan về mã tốt hơn nhiều, đặc biệt là trong khi tạo ứng dụng jQuery Mobile .
Ngoài ra còn có một sự kiện jQuery Mobile đặc biệt khác và nó được gọi là mobileinit . Khi jQuery Mobile khởi động , nó kích hoạt một sự kiện mobileinit trên đối tượng tài liệu. Để ghi đè cài đặt mặc định, liên kết chúng với mobileinit . Một trong những ví dụ điển hình về việc sử dụng mobileinit là tắt tải trang Ajax hoặc thay đổi hành vi của trình tải Ajax mặc định.
$(document).on("mobileinit", function(){
//apply overrides here
});
Trang sự kiện chuyển tiếp thứ tự
Đầu tiên tất cả các sự kiện có thể được tìm thấy ở đây: http://api.jquerymobile.com/carget/events/
Hãy nói rằng chúng ta có một trang A và một trang B, đây là thứ tự dỡ / tải:
trang B - sự kiện pagebeforecreate
trang B - sự kiện pagecreate
trang B - trang eventinit
Trang A - sự kiện pagebeforehide
trang A - pageremove sự kiện
Trang A - sự kiện pagehide
trang B - trang sự kiệnbeforeshow
Trang B - sự kiện pageshow
Để hiểu các sự kiện trang tốt hơn, hãy đọc điều này:
pagebeforeload
, pageload
Và pageloadfailed
được kích hoạt khi một trang bên ngoài được nạp
pagebeforechange
, pagechange
Và pagechangefailed
là trang sự kiện thay đổi. Những sự kiện này được kích hoạt khi người dùng đang điều hướng giữa các trang trong ứng dụng.
pagebeforeshow
, pagebeforehide
, pageshow
Và pagehide
là trang sự kiện chuyển đổi. Những sự kiện này được thực hiện trước, trong và sau khi chuyển đổi và được đặt tên.
pagebeforecreate
, pagecreate
Và pageinit
là dành cho trang khởi tạo.
pageremove
có thể bị sa thải và sau đó được xử lý khi một trang bị xóa khỏi DOM
Trang tải ví dụ jsFiddle: http://jsfiddle.net/Gajotres/QGnft/
Nếu AJAX không được bật, một số sự kiện có thể không kích hoạt.
Ngăn chặn chuyển trang
Nếu vì một lý do nào đó, việc chuyển trang cần phải được ngăn chặn trong một số điều kiện có thể được thực hiện với mã này:
$(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');;
}
}
});
Ví dụ này sẽ hoạt động trong mọi trường hợp bởi vì nó sẽ kích hoạt lúc cầu xin mọi chuyển đổi trang và điều quan trọng nhất là nó sẽ ngăn thay đổi trang trước khi chuyển trang có thể xảy ra.
Đây là một ví dụ hoạt động:
Ngăn chặn nhiều sự kiện ràng buộc / kích hoạt
jQuery Mobile
hoạt động theo một cách khác với các ứng dụng web cổ điển. Tùy thuộc vào cách bạn quản lý để liên kết các sự kiện của mình mỗi khi bạn truy cập một số trang, nó sẽ liên kết các sự kiện lặp đi lặp lại. Đây không phải là một lỗi, nó chỉ đơn giản là cách jQuery Mobile
xử lý các trang của nó. Ví dụ: hãy xem đoạn mã này:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Ví dụ làm việc của jsFiddle: http://jsfiddle.net/Gajotres/CCfL4/
Mỗi lần bạn truy cập trang sự kiện nhấp chuột #index sẽ bị ràng buộc với nút # nút kiểm tra . Kiểm tra nó bằng cách di chuyển từ trang 1 đến trang 2 và quay lại nhiều lần. Có một số cách để ngăn chặn vấn đề này:
Giải pháp 1
Giải pháp tốt nhất sẽ là sử dụng pageinit
để liên kết các sự kiện. Nếu bạn xem một tài liệu chính thức, bạn sẽ thấy rằng nó pageinit
sẽ kích hoạt CHỈ một lần, giống như tài liệu đã sẵn sàng, vì vậy không có cách nào các sự kiện sẽ bị ràng buộc lại. Đây là giải pháp tốt nhất vì bạn không có chi phí xử lý như khi xóa các sự kiện bằng phương thức tắt.
Ví dụ làm việc của jsFiddle: http://jsfiddle.net/Gajotres/AAFH8/
Giải pháp làm việc này được thực hiện trên cơ sở một ví dụ có vấn đề trước đó.
Giải pháp 2
Xóa sự kiện trước khi bạn liên kết nó:
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
Ví dụ làm việc của jsFiddle: http://jsfiddle.net/Gajotres/K8YmG/
Giải pháp 3
Sử dụng bộ chọn Bộ lọc jQuery, như thế này:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Bởi vì bộ lọc sự kiện không phải là một phần của khung jQuery chính thức, nó có thể được tìm thấy ở đây: http://www.codenoth.com/archives/2009/event-filter/
Tóm lại, nếu tốc độ là mối quan tâm chính của bạn thì Giải pháp 2 tốt hơn nhiều so với Giải pháp 1.
Giải pháp 4
Một cái mới, có lẽ là dễ nhất trong tất cả.
$(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;
}
});
});
Ví dụ làm việc của jsFiddle: http://jsfiddle.net/Gajotres/Yerv9/
Tnx cho sholsinger cho giải pháp này: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-fires-multipl-times/
pageChange quirks sự kiện - kích hoạt hai lần
Đôi khi sự kiện pagechange có thể kích hoạt hai lần và nó không liên quan gì đến vấn đề được đề cập trước đó.
Lý do sự kiện pagebeforechange xảy ra hai lần là do cuộc gọi đệ quy trong changePage khi toPage không phải là một đối tượng DOM được tăng cường jQuery. Đệ quy này là nguy hiểm, vì nhà phát triển được phép thay đổi toPage trong sự kiện. Nếu nhà phát triển luôn đặt toPage thành một chuỗi, trong trình xử lý sự kiện pagebeforechange, bất kể đó có phải là đối tượng hay không, một vòng lặp đệ quy vô hạn sẽ dẫn đến. Sự kiện tải trang vượt qua trang mới dưới dạng thuộc tính trang của đối tượng dữ liệu (Điều này cần được thêm vào tài liệu, hiện tại nó không được liệt kê). Do đó, sự kiện tải trang có thể được sử dụng để truy cập trang được tải.
Trong vài từ, điều này xảy ra bởi vì bạn đang gửi các tham số bổ sung thông qua pageChange.
Thí dụ:
<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>
Để khắc phục sự cố này, hãy sử dụng bất kỳ sự kiện trang nào được liệt kê theo thứ tự chuyển tiếp sự kiện Trang .
Thời gian thay đổi trang
Như đã đề cập, khi bạn thay đổi từ một trang jQuery Mobile sang một trang khác, thông thường bằng cách nhấp vào một liên kết đến một trang jQuery Mobile khác đã tồn tại trong DOM hoặc bằng cách gọi thủ công $ .mobile.changePage, một số sự kiện và hành động tiếp theo xảy ra. Ở cấp độ cao, các hành động sau đây xảy ra:
- Một quá trình thay đổi trang được bắt đầu
- Một trang mới được tải
- Nội dung cho trang đó là cải tiến nâng cấp (theo kiểu)
- Chuyển đổi (slide / pop / etc) từ trang hiện tại sang trang mới xảy ra
Đây là điểm chuẩn chuyển tiếp trung bình của trang:
Tải trang và xử lý: 3 ms
Trang nâng cao: 45 ms
Chuyển đổi: 604 ms
Tổng thời gian: 670 ms
* Những giá trị này được tính bằng mili giây.
Vì vậy, như bạn có thể thấy một sự kiện chuyển tiếp đang ăn gần 90% thời gian thực hiện.
Thao tác dữ liệu / tham số giữa các lần chuyển trang
Có thể gửi một tham số / s từ trang này sang trang khác trong quá trình chuyển trang. Nó có thể được thực hiện theo vài cách.
Tham khảo: https://stackoverflow.com/a/13932240/1848600
Giải pháp 1:
Bạn có thể truyền các giá trị với changePage:
$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
Và đọc chúng như thế này:
$(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>
giây.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>
Giải pháp 2:
Hoặc bạn có thể tạo một đối tượng JavaScript liên tục cho mục đích lưu trữ. Khi Ajax được sử dụng để tải trang (và trang không được tải lại theo bất kỳ cách nào) thì đối tượng đó sẽ vẫn hoạt động.
var storeObject = {
firstname : '',
lastname : ''
}
Ví dụ: http://jsfiddle.net/Gajotres/9KKbx/
Giải pháp 3:
Bạn cũng có thể truy cập dữ liệu từ trang trước như thế này:
$(document).on('pagebeforeshow', '#index',function (e, data) {
alert(data.prevPage.attr('id'));
});
prevPage đối tượng tốt nghiệp hoàn chỉnh trang trước.
Giải pháp 4:
Như một giải pháp cuối cùng, chúng tôi có một triển khai HTML tiện lợi của localStorage. Nó chỉ hoạt động với các trình duyệt HTML5 (bao gồm cả trình duyệt Android và iOS) nhưng tất cả dữ liệu được lưu trữ đều tồn tại thông qua việc làm mới trang.
if(typeof(Storage)!=="undefined") {
localStorage.firstname="Dragan";
localStorage.lastname="Gaic";
}
Ví dụ: http://jsfiddle.net/Gajotres/J9NTr/
Có lẽ là giải pháp tốt nhất nhưng nó sẽ thất bại trong một số phiên bản iOS 5.X. Đó là một lỗi cũng biết.
Không sử dụng .live()
/ .bind()
/.delegate()
Tôi quên đề cập (và tnx andleer để nhắc nhở tôi) sử dụng bật / tắt cho liên kết / hủy liên kết sự kiện, sống / chết và liên kết / hủy liên kết không được chấp nhận.
Phương thức .live () của jQuery được xem như một ơn trời khi nó được đưa vào API trong phiên bản 1.3. Trong một ứng dụng jQuery điển hình, có thể có rất nhiều thao tác DOM và nó có thể trở nên rất tẻ nhạt khi móc và gỡ ra khi các phần tử đến và đi. Các .live()
phương pháp làm cho nó có thể treo một sự kiện cho cuộc sống của các ứng dụng dựa trên chọn của nó. Tuyệt vời phải không? Sai, .live()
phương pháp cực kỳ chậm. Các .live()
phương pháp thực sự móc sự kiện cho các đối tượng tài liệu, có nghĩa là sự kiện bắt buộc bong bóng lên từ yếu tố đó tạo ra sự kiện này cho đến khi nó đạt đến tài liệu. Điều này có thể tốn thời gian đáng kinh ngạc.
Bây giờ nó không được dùng nữa. Mọi người trong nhóm jQuery không còn khuyến nghị sử dụng nó nữa và tôi cũng vậy. Mặc dù có thể tẻ nhạt để móc và gỡ các sự kiện, mã của bạn sẽ nhanh hơn nhiều nếu không có .live()
phương thức so với nó.
Thay vì .live()
bạn nên sử dụng .on()
. .on()
nhanh hơn khoảng 2-3 lần so với .live () . Hãy xem điểm chuẩn ràng buộc sự kiện này: http://jsperf.com/jquery-live-vs-delegate-vs-on 432 , mọi thứ sẽ rõ ràng từ đó.
Điểm chuẩn:
Có một kịch bản xuất sắc được tạo cho điểm chuẩn sự kiện trang jQuery Mobile . Nó có thể được tìm thấy ở đây: https://github.com/jquery/jquery-mobile/blob/master/tools/page-change-time.js . Nhưng trước khi bạn làm bất cứ điều gì với nó, tôi khuyên bạn nên xóa alert
hệ thống thông báo của nó (mỗi trang thay đổi của Cameron sẽ hiển thị cho bạn dữ liệu này bằng cách tạm dừng ứng dụng) và thay đổi nó thành console.log
chức năng.
Về cơ bản tập lệnh này sẽ ghi lại tất cả các sự kiện trang của bạn và nếu bạn đọc kỹ bài viết này (mô tả sự kiện trang), bạn sẽ biết jQm đã dành bao nhiêu thời gian cho việc cải tiến trang, chuyển trang ....
Ghi chú cuối cùng
Luôn luôn, và ý tôi là luôn đọc tài liệu chính thức của jQuery Mobile . Nó thường sẽ cung cấp cho bạn thông tin cần thiết, và không giống như một số tài liệu khác, tài liệu này khá tốt, với đủ giải thích và ví dụ mã.
Thay đổi:
- 30.01.2013 - Đã thêm một phương pháp mới trong phòng ngừa kích hoạt nhiều sự kiện
- 31.01.2013 - Đã thêm một sự làm rõ tốt hơn cho chương Thao tác dữ liệu / Tham số giữa các lần chuyển trang
- 03.02.2013 - Đã thêm nội dung / ví dụ mới vào chương Thao tác dữ liệu / tham số giữa các lần chuyển trang
- 22.05.2013 - Đã thêm giải pháp ngăn chặn chuyển đổi / thay đổi trang và thêm liên kết đến tài liệu API chính thức của sự kiện
- 18.05.2013 - Đã thêm một giải pháp khác chống lại nhiều ràng buộc sự kiện