我正在使用jQuery Mobile,我很难理解经典文档准备和jQuery Mobile页面事件之间的差异。
真正的区别是什么? 为什么要 <!——language: lang-js——> $ (document)时(){ }); 比… $(文档)。(pageinit) { }); 当您从一个页面转换到另一个页面时,页面事件的顺序是什么? 如何将数据从一个页面发送到另一个页面,是否可以访问前一页的数据?
我正在使用jQuery Mobile,我很难理解经典文档准备和jQuery Mobile页面事件之间的差异。
真正的区别是什么? 为什么要 <!——language: lang-js——> $ (document)时(){ }); 比… $(文档)。(pageinit) { }); 当您从一个页面转换到另一个页面时,页面事件的顺序是什么? 如何将数据从一个页面发送到另一个页面,是否可以访问前一页的数据?
当前回答
这是正确的方法:
要执行仅对索引页可用的代码,可以使用以下语法:
$(document).on('pageinit', "#index", function() {
...
});
其他回答
有些人可能会觉得这很有用。只需复制粘贴到你的页面,你会得到一个序列,其中事件是在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');});
您不会在控制台中看到unload,因为它是在页面卸载时(当您离开页面时)触发的。像这样使用它:
$(window).unload(function () { debugger; console.log("window unloaded");});
你会明白我的意思。
在jQuery-mobile中,文档准备和页面事件之间的简单区别是:
文档就绪事件用于整个HTML页面, 美元(文档)时函数(e) { //你的代码 }); 当存在页面事件时,用于处理特定的页面事件: <div data-role="page" id="second"> < div data-role = "头" > < h3 > 页眉 < / h3 > < / div > < div data-role = "内容" > 页面内容 < / div > < !——内容- - > < div data-role = >“页脚” 页脚 < / div > < !页脚- > < / div > < !-页面- >
你也可以使用document来处理pageinit事件:
$(document).on('pageinit', "#mypage", function() {
});
这是正确的方法:
要执行仅对索引页可用的代码,可以使用以下语法:
$(document).on('pageinit', "#index", function() {
...
});
jQuery Mobile 1.4更新:
我最初的文章是针对旧的页面处理方式,基本上是jQuery Mobile 1.4之前的所有内容。旧的处理方式现在已弃用,它将一直活跃到(包括)jQuery Mobile 1.5,所以你仍然可以使用下面提到的所有东西,至少到明年的jQuery Mobile 1.6。
旧的事件,包括pageinit都不存在了,它们被页面容器小部件所取代。Pageinit会被完全擦除,你可以用pagcreate代替,那个事件保持不变,它不会被改变。
如果您对页面事件处理的新方法感兴趣,请查看这里,如果有其他情况,请继续阅读本文。即使你使用的是jQuery Mobile 1.4 +,你也应该阅读这个答案,它超越了页面事件,所以你可能会发现很多有用的信息。
旧的内容:
这篇文章也可以在我的博客中找到。
$(document).on('pageinit') vs $(document).ready()
The first thing you learn in jQuery is to call code inside the $(document).ready() function so everything will execute as soon as the DOM is loaded. However, in jQuery Mobile, Ajax is used to load the contents of each page into the DOM as you navigate. Because of this $(document).ready() will trigger before your first page is loaded and every code intended for page manipulation will be executed after a page refresh. This can be a very subtle bug. On some systems it may appear that it works fine, but on others it may cause erratic, difficult to repeat weirdness to occur.
经典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移动应用程序时。
还有另一个特殊的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,这是一个卸载/加载顺序:
page B -事件页面生成前 页面B -事件页面创建 page B - event pageinit page A -事件pagebeforehide 页面A -事件页面移动 page A -事件页面隐藏 page B -事件pagebeforeshow 页面B -事件页面显示
为了更好地理解页面事件,请阅读以下内容:
pagebeforeload, pageload and pageloadfailed are fired when an external page is loaded pagebeforechange, pagechange and pagechangefailed are page change events. These events are fired when a user is navigating between pages in the applications. pagebeforeshow, pagebeforehide, pageshow and pagehide are page transition events. These events are fired before, during and after a transition and are named. pagebeforecreate, pagecreate and pageinit are for page initialization. pageremove can be fired and then handled when a page is removed from the 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/
每次你访问页面#索引点击事件将被绑定到按钮#测试按钮。通过从第1页移到第2页并返回几次来测试它。预防这个问题的方法很少:
解决方案1
最好的解决方案是使用pageinit来绑定事件。如果你看一下官方文档,你会发现pageinit只会触发一次,就像document ready一样,所以没有办法再次绑定事件。这是最好的解决方案,因为您不需要像使用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事件异常——触发两次
有时页面更改事件可以触发两次,它与前面提到的问题没有任何关系。
The reason the pagebeforechange event occurs twice is due to the recursive call in changePage when toPage is not a jQuery enhanced DOM object. This recursion is dangerous, as the developer is allowed to change the toPage within the event. If the developer consistently sets toPage to a string, within the pagebeforechange event handler, regardless of whether or not it was an object an infinite recursive loop will result. The pageload event passes the new page as the page property of the data object (This should be added to the documentation, it's not listed currently). The pageload event could therefore be used to access the loaded page.
简而言之,这是因为您通过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:
作为最后一个解决方案,我们有一个漂亮的localStorage的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已弃用。
The .live() method of jQuery was seen as a godsend when it was introduced to the API in version 1.3. In a typical jQuery app there can be a lot of DOM manipulation and it can become very tedious to hook and unhook as elements come and go. The .live() method made it possible to hook an event for the life of the app based on its selector. Great right? Wrong, the .live() method is extremely slow. The .live() method actually hooks its events to the document object, which means that the event must bubble up from the element that generated the event until it reaches the document. This can be amazingly time consuming.
现在已弃用。jQuery团队的人不再推荐使用.live()方法,我也不推荐。尽管钩子和解钩子事件可能很乏味,但如果没有.live()方法,代码会比使用它快得多。
你应该使用.on()而不是.live(). 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。但在你对它做任何事情之前,我建议你删除它的警报通知系统(每个“更改页面”将通过停止应用程序向你显示这些数据),并将其更改为console.log功能。
基本上,这个脚本将记录所有的页面事件,如果您仔细阅读本文(页面事件描述),您将知道jQm在页面增强、页面转换....上花费了多少时间
最后指出
始终,我的意思是始终阅读jQuery Mobile官方文档。它通常会为您提供所需的信息,与其他文档不同的是,这个文档相当不错,有足够的解释和代码示例。
变化:
30.01.2013 -增加了一个新的方法多事件触发预防 31.01.2013 -增加了一个更好的说明章节数据/参数操作之间的页面转换 03.02.2013 -增加了新的内容/例子章节之间的页面转换数据/参数操作 22.05.2013 -增加了防止页面转换/更改的解决方案,并添加了官方页面事件API文档的链接 18.05.2013 -增加了另一个针对多事件绑定的解决方案
当您使用.on()时,它基本上是您正在使用的一个实时查询。
另一方面,.ready(在您的例子中)是一个静态查询。在使用它时,您可以动态地更新数据,而不必等待页面加载。当输入特定值时,可以简单地将值传递到数据库中(如果需要)。
在输入数据(帐户、帖子甚至评论)的表单中,经常使用实时查询。