小编典典

jQuery Mobile准备文档与页面事件

html

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

  1. 真正的区别是什么?

为何要

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

$(document).ready() {

});

胜过

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

});
  1. 从一页切换到另一页时,页面事件的顺序是什么?

  2. 如何将数据从一页发送到另一页,并且可以访问前一页的数据?


阅读 279

收藏
2020-05-10

共1个答案

小编典典

jQuery Mobile 1.4更新:

我的原始文章旨在用于旧的页面处理方式,基本上是jQuery Mobile
1.4之前的所有内容。现在不赞成使用旧的处理方式,它会一直保持有效状态,直到(包括)jQuery Mobile
1.5,因此您仍然可以使用下面提到的所有功能,至少直到明年和jQuery Mobile 1.6为止。

旧事件,包括 pageinit 不存在了,它们被替换为 pagecontainer 部件。 Pageinit
已被完全擦除,您可以使用 pagecreate 来代替,该事件保持不变,并且不会被更改。

如果您对页面事件处理的新方法感兴趣。即使您正在使用jQueryMobile1.4或更高版本,也应该阅读此答案,它不仅仅包含页面事件,因此您可能会发现很多有用的信息。

较旧的内容:

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

jQuery中 学习的第一件事是在 $(document).ready()函数内部调用代码,以便所有内容都将在DOM加载后立即执行。但是,在 jQuery Mobile中,Ajax用于在导航时将每个页面的内容加载到DOM中。因此,这$(document).ready()将在加载第一个页面之前触发,并且打算在页面刷新后执行所有用于页面操作的代码。这可能是一个非常微妙的错误。在某些系统上,它似乎可以正常工作,但在其他系统上,则可能导致不稳定,难以重复的怪异现象发生。

经典jQuery语法:

$(document).ready(function() {

});

为了解决此问题(并相信我这是一个问题),jQueryMobile开发人员创建了页面事件。简而言之,页面事件是在页面执行的特定点触发的事件。这些页面事件之一是 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 事件。

关于这个问题的更多笔记。无论您使用的是1个html多个页面还是多个HTML文件范例,建议您将所有自定义JavaScript页面处理都分成一个单独的JavaScript文件。这将使您的代码变得更好,但是您将获得更好的代码概述,尤其是在创建
jQuery Mobile 应用程序时。

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

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

页面事件转换顺序

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

  1. 页面B-事件 pagebeforecreate

  2. 页面B-事件页面 创建

  3. 页面B-事件 pageinit

  4. A页-事件 pagebehidehide

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

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

  7. 页面B-事件 页面

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

为了更好地了解页面事件,请阅读以下内容:

  • pagebeforeloadpageloadpageloadfailed 在加载外部页面时触发
  • pagebeforechangepagechangepagechangefailed 在页面更改事件。当用户在应用程序中的页面之间导航时,将触发这些事件。
  • pagebeforeshowpagebeforehidepageshowpagehide 是页面转换事件。这些事件在转换之前,期间和之后都会触发,并被命名。
  • pagebeforecreatepagecreate 并且 pageinit 是页面初始化。
  • pageremove 从DOM中删除页面后,可以将其触发并进行处理

如果未启用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');
    });
});

每次您访问页面 #index click事件都会绑定到 #test-button按钮
。从第1页移至第2页并多次返回进行测试。有几种方法可以防止此问题:

解决方案1

最好的解决方案是使用 pageinit 绑定事件。如果您查看正式文档,就会发现 pageinit
仅触发一次,就像准备好文档一样,因此不可能再次绑定事件。这是最好的解决方案,因为您没有像使用off方法删除事件时那样的处理开销。

该工作解决方案是在先前有问题的示例的基础上提出的。

解决方案2

在绑定事件之前将其删除:

$(document).on('pagebeforeshow', '#index', function(){
    $(document).off('click', '#test-button').on('click', '#test-button',function(e) {
        alert('Button click');
    });
});

解决方案3

使用jQuery筛选器选择器,如下所示:

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

简而言之,如果您最关心速度,那么 解决方案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;
        }
    });
});

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%的执行时间。

页面转换之间的数据/参数操作

在页面转换期间可以将参数从一个页面发送到另一页面。它可以通过几种方式来完成。

解决方案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 : ''
}

解决方案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";
}

可能是最佳解决方案,但在某些版本的iOS 5.X中将失败。这是一个众所周知的错误。

不要使用.live()/ .bind()/.delegate()

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

现在已弃用。jQuery团队的人们不再推荐使用它,我也不推荐使用。即使挂接和取消挂接事件可能很繁琐,但没有该.live()方法的代码将比使用该方法更快。

而不是 .live() 您应该使用 .on().on().live()
快大约2-3倍。看一下这个事件绑定基准:
live-vs-delegate-vs-on/34),从那里可以清楚地看到所有内容。

基准测试:

jQuery Mobile

change-time.js)。但是在您执行任何操作之前,我建议您删除其 alert
通知系统(每个“更改页”都将通过停止该应用程序向您显示此数据)并将其更改为 console.log 功能。

基本上,此脚本将记录您的所有页面事件,如果您仔细阅读本文(页面事件描述),您将知道jQm在页面增强,页面转换…上花费了多少时间。

最后的笔记

总是,我的意思是总是阅读 jQuery Mobile
官方文档。它通常会为您提供所需的信息,并且与某些其他文档不同,该文档非常好,带有足够的解释和代码示例。

变化:

  • 30.01.2013-添加了防止多事件触发的新方法
  • 2013年1月31日-为 页面转换之间的数据/参数操作* 一章添加了更好的说明 *
  • 2013年3月2日- 在页面转换之间的数据/参数操作* 一章中添加了新的内容/示例 *
  • 2013年5月22日-添加了用于防止页面过渡/更改的解决方案,并添加了指向官方页面事件API文档的链接
  • 2013年5月18日-添加了另一个针对多个事件绑定的解决方案
2020-05-10