我正在使用jQuery Mobile,并且无法理解经典文档就绪和jQuery Mobile页面事件之间的区别。
真正的区别是什么?
为何要
<!-- language: lang-js --> $(document).ready() { });
胜过
$(document).on('pageinit') { });
从一页切换到另一页时,页面事件的顺序是什么?
如何将数据从一页发送到另一页,并且可以访问前一页的数据?
我正在使用jQuery Mobile,并且无法理解经典文档就绪和jQuery Mobile页面事件之间的区别。
真正的区别是什么?
为何要
<!-- language: lang-js -->
$(document).ready() {
});
胜过
$(document).on('pageinit') {
});
从一页切换到另一页时,页面事件的顺序是什么?
如何将数据从一页发送到另一页,并且可以访问前一页的数据?
Answers:
我的原始文章旨在用于旧的页面处理方式,基本上是jQuery Mobile 1.4之前的所有内容。现在不赞成使用旧的处理方式,它会一直保持有效状态,直到(包括)jQuery Mobile 1.5,因此您仍然可以使用下面提到的所有功能,至少直到明年和jQuery Mobile 1.6为止。
旧事件,包括pageinit不存在了,它们被替换为pagecontainer部件。Pageinit被完全擦除,您可以使用pagecreate来代替,该事件保持不变,并且不会被更改。
如果您对页面事件处理的新方法感兴趣,请在此处查看,在任何其他情况下,请继续阅读本文。即使您使用的是jQuery Mobile 1.4 +,您也应该阅读此答案,它不仅仅涉及页面事件,因此您可能会发现很多有用的信息。
这篇文章也可以在我的博客HERE中找到。
$(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() {
});
我们可以走得更远,使用页面ID代替文档选择器。假设我们有一个带有ID 索引的 jQuery Mobile页面:
<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-事件pagebeforecreate
页面B-事件页面创建
页面B-事件pageinit
A页-事件pagebehidehide
页面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
与传统Web应用程序的工作方式不同。根据每次访问某个页面时如何绑定事件的方式,它将一遍又一遍地绑定事件。这不是错误,它只是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/
对于此解决方案,请向sholsinger发送Tnx:http : //sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
pageChange事件怪癖-触发两次
有时pagechange事件可以触发两次,并且与前面提到的问题没有任何关系。
pagebeforechange事件发生两次的原因是由于toPage不是jQuery增强的DOM对象时changePage中的递归调用。这种递归很危险,因为允许开发人员在事件中更改toPage。如果开发人员在pagebeforechange事件处理程序中始终将toPage设置为字符串,则无论它是否是对象,都将导致无限递归循环。pageload事件将新页面作为数据对象的page属性传递(应将其添加到文档中,当前未列出)。因此,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页面更改为另一个页面时,通常是通过单击DOM中已经存在的另一个jQuery Mobile页面的链接,或者通过手动调用$ .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实现。它仅适用于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提醒我)不建议使用on / off进行事件绑定/解除绑定,不赞成使用live / die和bind / unbind。
jQuery的.live()方法在1.3版引入API时被视为天赐之物。在典型的jQuery应用程序中,可能会有很多DOM操作,并且随着元素的来去去去钩挂和脱钩变得非常繁琐。该.live()
方法可以根据应用程序的选择器在应用程序的生命周期中挂钩事件。很好吗?错误,该.live()
方法非常慢。的.live()
方法实际上将其事件挂接到文档对象,这意味着该事件必须从生成该事件的元素起泡直到到达文档。这可能非常耗时。
现在已弃用。jQuery团队的人们不再推荐使用它,我也不推荐使用。即使挂接和取消挂接事件可能很繁琐,但如果不使用jQuery,您的代码将更快。.live()
方法的将比使用它。
而不是.live()
您应该使用.on()
。.on()
比.live()快大约2-3倍。看一下该事件绑定基准: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官方文档。它通常会为您提供所需的信息,并且与某些其他文档不同,该文档非常好,带有足够的说明和代码示例。
$().live()
在jQuery 1.7中被贬值,在1.9中被删除,因此它确实应该成为任何jQuery Mobile解决方案的一部分。jQM 1.7的当前最低核心版本。
pagecreate
首次创建页面时,事件仅触发一次。因此,如果我们在其中绑定点击事件,pagecreate
它将不会多次触发。我在开发应用程序时发现了一些问题。但是我们不能总是使用pagecreate
绑定事件,因此您提供的解决方案是最好的。+1给予
你们中的有些人可能会发现这很有用。只需将其复制粘贴到您的页面上,您将获得在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");});
您会明白我的意思。
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() {
});