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



真正的区别是什么?
< br为何为什么

<!-- language: lang-js -->

$(document).ready() {

});




 
 $(document).on('pageinit') {

});
  

,当您从一页转换到另一页时,页面事件的顺序是什么?
如何将数据从一页发送到另一页,并且可以访问前一页的数据?


评论

在问题1下,它们都是相同的。您可以更改它还是解释更多您的意思?

因此,不到一年后,就发生了pageinit事件,“在1.4.0中不推荐使用此事件,而支持pagecreate”。参见api.jquerymobile.com/pageinit

#1 楼

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') vs $(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-事件页面beforecreate
页面B-事件页面create
页面B-事件pageinit
页面A-事件页面beforehide
页面A-事件页面删除
页面A-事件页面隐藏
页面B-事件页面beforeshow
页面B-事件页面显示

为了更好地了解页面事件,请阅读:



加载外部页面时会触发pagebeforeloadpageloadpageloadfailed

pagebeforechangepagechangepagechangefailed是页面更改事件。当用户在应用程序中的页面之间导航时,将触发这些事件。

pagebeforeshowpagebeforehidepageshowpagehide是页面转换事件。这些事件在转换之前,期间和之后被触发并被命名。

pagebeforecreatepagecreatepageinit用于页面初始化。

pageremove可以被触发,然后在页面已从DOM中删除

页面加载jsFiddle示例:http://jsfiddle.net/Gajotres/QGnft/


如果未启用AJAX,则某些事件可能不会触发。


防止页面转换

如果出于某种原因在某些情况下需要防止页面转换,可以使用以下代码进行: br />
$(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页并多次返回进行测试。有几种方法可以防止此问题:

解决方案1 ​​

最佳解决方案是使用pageinit绑定事件。如果您查看官方文档,就会发现pageinit仅会触发一次,就像准备好文档一样,因此不可能再次绑定事件。这是最好的解决方案,因为您没有像使用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 Filter选择器,像这样:

$('#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

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

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

为此,向骗子致谢解决方法: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&amp;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提醒我) / off用于事件绑定/解除绑定,不建议使用live / die和bind / unbind。

jQuery的.live()方法在1.3版引入API时被视为天赐之物。在典型的jQuery应用程序中,可能会有很多DOM操作,并且随着元素的来去去去钩挂和脱钩会变得非常繁琐。通过使用.live()方法,可以根据其选择器在应用程序的生命期内挂起事件。很好吗?错误的.live()方法非常慢。 .live()方法实际上将其事件挂接到文档对象,这意味着该事件必须从生成该事件的元素起泡直到到达文档。这可能会非常耗时。

现在已弃用。 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文档。它通常会为您提供所需的信息,并且与某些其他文档不同,该文档非常好,具有足够的解释和代码示例。

更改:


30.01 .2013-添加了一种防止多事件触发的新方法
31.01.2013-为页面过渡之间的数据/参数操作一章添加了更好的说明

03.02.2013-添加了新的内容/示例页面过渡之间的数据/参数操作一章

22.05.2013-添加了防止页面过渡/更改的解决方案,并添加了指向官方页面事件API文档的链接
18.05.2013-添加了防止多事件绑定的另一种解决方案


评论


$()。live()在jQuery 1.7中已贬值,在1.9中已删除,因此它确实应该成为任何jQuery Mobile解决方案的一部分。 jQM 1.7的当前最低核心版本。

– andleer
13年1月22日在22:20



+1关于页面加载周围的关键行为的非常有用的摘要

– D'Arcy Rittich
13年1月27日在5:32

pagecreate事件仅在首次创建页面时触发一次。因此,如果我们在pagecreate内绑定点击事件,它将不会多次触发。我在开发应用程序时发现了一些问题。但是我们不能总是使用pagecreate绑定事件,因此您提供的解决方案是最好的。 +1

–杰伊·马尤(Jay Mayu)
2013年3月20日4:26



您有pageBeforeShow列出两次。它被列为5号和8号。它被调用两次吗?

–Chase Roberts
2014年6月30日22:38在

那是一个错字,我已经解决了,pagebeforeshow只会触发一次。感谢您的注意。

– Gajotres
2014年7月1日9:17



#2 楼

你们中的有些人可能会发现这很有用。只需将其复制粘贴到您的页面上,您将获得在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");});


您会明白我的意思。

#3 楼

这是正确的方法:

要执行仅对索引页可用的代码,我们可以使用以下语法:

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


评论


上面的答案是一样的,你不觉得吗? :)

–奥马尔
13年8月15日在9:03

感谢您提供的快速修复简短解答。 :-)

– SharppC
6月6日19:22

#4 楼

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() {

});


#5 楼

当您使用.on()时,它基本上是您正在使用的实时查询。

另一方面,.ready(根据您的情况)是静态查询。使用它时,您可以动态更新数据,而不必等待页面加载。输入特定值后,您可以简单地将值传递到数据库中(如果需要)。

实时查询在我们输入数据(帐户或帖子甚至评论)的表单中很常见。 。