jQuery Mobile:文档准备与页面事件

我正在使用jQuery Mobile,而且我无法理解经典文档就绪和jQuery Mobile页面事件之间的差异。

  1. 真正的区别是什么?

    为什么要

    <!-- language: lang-js --> $(document).ready() { }); 

    比…更好

     $(document).on('pageinit') { }); 
  2. 当你从一个页面转换到另一个页面时,页面事件的顺序是什么?

  3. 如何将数据从一个页面发送到另一个页面,是否可以访问前一页的数据?

jQuery Mobile 1.4更新:

我原来的文章是为旧的页面处理方式,基本上在jQuery Mobile 1.4之前的一切。 旧的处理方式现在已经被弃用了,直到(包括)jQuery Mobile 1.5才能继续运行,所以你仍然可以使用下面提到的所有东西,至less到明年和jQuery Mobile 1.6。

包括pageinit在内的旧事件不再存在,它们被pagecontainer小部件取代。 Pageinit完全被清除,你可以使用pagecreate来代替,事件保持不变,不会被改变。

如果您对页面事件处理的新方式感兴趣,请在这里查看 ,在任何其他情况下请随时继续阅读本文。 即使你使用jQuery Mobile 1.4 +,你也应该阅读这个答案,它不仅仅是页面事件,你可能会发现很多有用的信息。

较旧的内容:

这篇文章也可以作为我的博客HERE的一部分。

$(document).on('pageinit') vs $(document).ready()

你在jQuery中学到的第一件事就是调用$(document).ready()函数中的代码,这样一旦DOM被加载,所有的东西都会被执行。 但是,在jQuery Mobile中 ,Ajax用于在浏览时将每个页面的内容加载到DOM中。 由于这个$(document).ready()会在加载第一页之前触发,并且每一次页面操作的代码都将在页面刷新后执行。 这可能是一个非常微妙的错误。 在某些系统上,它可能performance得很好,但在其他系统上可能会导致不稳定,难以重复发生。

经典的jQuery语法:

 $(document).ready(function() { }); 

为了解决这个问题(并相信我,这是一个问题) jQuery Mobile开发人员创build页面事件。 简而言之,页面事件是在页面执行的特定点触发的事件。 其中一个页面事件是一个pageinit事件,我们可以像这样使用它:

 $(document).on('pageinit', function() { }); 

我们可以更进一步,使用页面id而不是文档select器。 比方说,我们有一个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事件将在每次页面将被加载并首次显示时执行。 除非手动刷新页面或closuresAjax页面加载,否则不会再次触发。 如果您希望每次访问页面时执行代码,最好使用pagebeforeshow事件。

这里有一个工作的例子: http : //jsfiddle.net/Gajotres/Q3Usv/来演示这个问题。

关于这个问题还有很多笔记。 无论您是使用1个HTML页面还是多个HTML文件范例,build议将您的所有自定义JavaScript页面处理分隔成一个单独的JavaScript文件。 这会注意到你的代码更好,但是你会有更好的代码概述,特别是在创build一个jQuery Mobile应用程序的时候。

还有另一个特殊的jQuery Mobile事件,它被称为mobileinit 。 当jQuery Mobile启动时,它触发文档对象上的mobileinit事件。 要覆盖默认设置,请将它们绑定到mobileinitmobileinit使用的一个很好的例子是closuresAjax页面加载,或者更改默认的Ajax加载器行为。

 $(document).on("mobileinit", function(){ //apply overrides here }); 

页面事件转换顺序

首先所有的事件可以在这里find: http : //api.jquerymobile.com/category/events/

比方说,我们有一个页面A和一个页面B,这是一个卸载/加载顺序:

  1. 页面B – 事件pagebeforecreate

  2. 页面B – 事件页面创build

  3. 页面B – 事件pageinit

  4. 页面A – 事件pagebeforehide

  5. 页面A – 事件页面删除

  6. 页面A – 事件页面隐藏

  7. 页面B – 事件页面显示

  8. 页面B – 活动页面显示

为了更好的页面事件理解阅读:

  • pagebeforeloadpagebeforeloadpagebeforeload在加载外部页面时触发
  • pagebeforechangepagechangepagechangefailed是页面更改事件。 当用户在应用程序中的页面之间导航时,会触发这些事件。
  • pagebeforeshowpagebeforehidepageshowpagehide是页面转换事件。 这些事件在过渡之前,之中和之后被解雇并被命名。
  • pagebeforecreatepagecreatepageinit用于页面初始化。
  • 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点击事件将被绑定到button #test-button 。 通过从第1页移动到第2页并回几次进行testing。 有几种方法来防止这个问题:

解决scheme1

最好的解决scheme是使用pageinit绑定事件。 如果你看一下官方的文档,你会发现pageinit只会触发一次,就像文档准备好一样,所以再也无法绑定事件了。 这是最好的解决scheme,因为您没有像使用off方法删除事件一样的处理开销。

工作jsFiddle例子: http : //jsfiddle.net/Gajotres/AAFH8/

这个工作解决scheme是基于以前有问题的例子。

解决scheme2

在绑定之前删除事件:

 $(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/

解决scheme3

使用一个jQuery筛选器select器,如下所示:

 $('#carousel div:Event(!click)').each(function(){ //If click is not bind to #carousel div do something }); 

由于事件filter不是官方jQuery框架的一部分,可以在这里find: http : //www.codenothing.com/archives/2009/event-filter/

简而言之,如果速度是您主要关心的问题,则解决scheme2比解决scheme1好得多。

解决scheme4

一个新的,可能是最简单的。

 $(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到这个解决scheme的sholsinger : http : //sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

pageChange事件怪癖 – 触发两次

有时pagechange事件可能会触发两次,与之前提到的问题没有任何关系。

pagebeforechange事件发生两次的原因是由于recursion调用changePage时,toPage不是一个jQuery增强的DOM对象。 这种recursion是危险的,因为开发者被允许在事件内改变toPage。 如果开发人员在pagebeforechange事件处理程序中始终将toPage设置为string,则无论该对象是否为对象,都将导致无限recursion循环。 页面加载事件传递新的页面作为数据对象的页面属性(这应该被添加到文档中,目前没有列出)。 pageload事件因此可以用来访问加载的页面。

几句话就是这样,因为你通过pageChange发送了额外的参数。

例:

 <a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&amp;name=Sat"><h3>Sat</h3></a> 

要解决此问题,请使用页面事件转换顺序中列出的任何页面事件。

页面更改时间

如前所述,当您从一个jQuery Mobile页面切换到另一个页面时,通常是通过单击指向DOM中已经存在的另一个jQuery Mobile页面的链接,或者通过手动调用$ .mobile.changePage,发生多个事件和后续操作。 在高层次上,会发生以下操作:

  • 页面更改过程开始
  • 一个新的页面被加载
  • 该页面的内容是“增强”(样式)
  • 发生从现有页面到新页面的转换(滑动/popup/等)

这是一个平均页面转换基准:

页面加载和处理: 3毫秒

页面增强: 45毫秒

过渡: 604毫秒

总时间: 670毫秒

*这些值以毫秒为单位。

所以你可以看到一个转换事件正在吃掉将近90%的执行时间。

数据/参数在页面转换之间进行操作

在页面转换过程中,可以将一个参数从一个页面发送到另一个页面。 这可以通过几种方式来完成。

参考: https : //stackoverflow.com/a/13932240/1848600

解决scheme1:

您可以使用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> 

你们有些人可能会觉得这很有用。 只需将其粘贴到您的网页上,即可获得在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中文档就绪和页面事件的简单区别在于:

  1. 文档就绪事件用于整个HTML页面,

     $(document).ready(function(e) { // Your code }); 
  2. 当有页面事件时,用于处理特定的页面事件:

     <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(如你的情况)是一个静态查询。 在使用它时,您可以dynamic更新数据,而不必等待页面加载。 当input一个特定的值时,您可以简单地将值传递到数据库(如果需要的话)。

实时查询的使用在input数据(帐户或post甚至评论)的表单中很常见。