我使用的是jQuery Mobile,很难理解classic 文档就绪和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,所以您仍然可以使用下面提到的所有内容,至少直到明年和jQuery Mobile 1.6.

旧事件(包括pageinit个)已不复存在,取而代之的是pagecontainer个小部件.Pageinit被完全擦除,你可以用pagecreate代替,该事件保持不变,不会改变.

如果您对页面事件处理的新方法感兴趣,请看100,在任何其他情况下,请继续阅读本文.即使您使用的是jQuery Mobile 1.4+,您也应该阅读这个答案,它超出了页面事件的范围,因此您可能会找到很多有用的信息.

较旧的内容:

这篇文章也可以在我的博客100中找到.

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

您在jQuery中学到的第一件事是调用100函数内的代码,以便加载DOM后立即执行所有操作.但是,在jQuery Mobile中,在导航时使用Ajax将每个页面的内容加载到DOM中.因此,100将在加载第一个页面之前触发,并且所有用于页面操作的代码都将在页面刷新之后执行.这可能是一个非常微妙的错误.在一些系统上,它可能看起来运行良好,但在另一些系统上,它可能会导致不稳定的、难以重复的怪异现象发生.

classic jQuery语法:

$(document).ready(function() {

});

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

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

});

我们可以更进一步,使用页面id而不是文档 Select 器.假设我们有一个id为index的jQuery移动页面:

<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,这是一个卸载/加载顺序:

  1. B页-事件100

  2. B页-事件100

  3. B页-事件100

  4. A页-活动100

  5. A页-活动100

  6. A页-活动100

  7. B页-事件100

  8. B页-事件100

For better page events understanding read this:

  • 加载外部页面时会触发100101102
  • 100101102是页面更改事件.当用户在应用程序中的页面之间导航时,会触发这些事件.
  • 100101102103是页面转换事件.这些事件在转换之前、期间和之后激发,并被命名.
  • 100101102用于页面初始化.
  • 100可以被激发,然后在从DOM中删除页面时进行处理

页面加载JSFIDLE示例: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');;
        }
    }
});

这个例子在任何情况下都会起作用,因为它会在每次页面转换请求时触发,最重要的是它会在页面转换发生之前阻止页面更改.

以下是一个有效的示例:

防止多事件绑定/触发

100的工作方式与classic web应用程序不同.根据您每次访问某个页面时如何绑定事件,它会一次又一次地绑定事件.这不是一个错误,这只是100处理页面的方式.例如,请看以下代码片段:

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

正在工作的JSFIDLE示例:http://jsfiddle.net/Gajotres/CCfL4/

每次访问第#index页时,点击事件都将绑定到按钮#test-button.通过从第1页移动到第2页,再返回几次来测试它.有几种方法可以防止这个问题:

解决方案1

最佳解决方案是使用100绑定事件.如果您查看官方文档,您会发现100只会触发一次,就像Document Ready一样,所以事件不可能再次绑定.这是最好的解决方案,因为您没有使用off方法删除事件时的处理开销.

工作jsFdle示例: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');
    });
});

正在工作的JSFIDLE示例:http://jsfiddle.net/Gajotres/K8YmG/

解决方案3

使用jQuery过滤 Select 器,如下所示:

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

因为事件过滤不是官方jquery框架的一部分,所以可以在这里找到

简而言之,如果速度是你主要关心的问题,那么解决方案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;
        }
    });
});

正在工作的JSFIDLE示例:http://jsfiddle.net/Gajotres/Yerv9/

对于此解决方案,TNX为sholsinger:http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/

pageChange event quirks - triggering twice

有时Page Change事件可以触发两次,它与前面提到的问题没有任何关系.

pagebeforechange事件发生两次的原因是,当toPage不是jQuery增强的DOM对象时,在changePage中进行递归调用.这种递归是危险的,因为开发者可以在事件中更改toPage.如果开发人员在pagebeforechange事件处理程序中始终将toPage设置为字符串,无论它是否是对象,都将导致无限递归循环.pageload事件将新页面作为数据对象的页面属性传递(这应该添加到文档中,当前未列出).因此,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移动页面切换到另一个jQuery移动页面时,通常通过单击指向DOM中已存在的另一个jQuery移动页面的链接,或者手动调用$.可移动的更改页面时,会发生多个事件和后续操作.在高级别上,会发生以下操作:

  • 页面更改过程开始
  • 将加载一个新页面
  • 该页面的内容为"增强"(样式化)
  • 发生从现有页面到新页面的转换(幻灯片/弹出窗口等

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

页面加载和处理:3 ms

页码:45 ms

过渡:604 ms

总时间:670 ms

*这些值以毫秒为单位.

因此,正如您所看到的,转换事件占用了几乎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);
});

Example:

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/

Probably best solution but it will fail in some versions of iOS 5.X. It is a well know error.

Don’t Use .live() / .bind() / .delegate()

我忘了提(tnxandleer提醒我)使用on/off进行事件绑定/解绑,不推荐使用live/die和bind/unbind.

这个jQuery的live()方法在1.3版的API中引入时被视为天赐良机.在一个典型的jQuery应用程序中,可能会有很多DOM操作,当元素来来go go go 时,钩住和解开钩子会变得非常乏味..live()方法可以根据应用程序的 Select 器在应用程序的生命周期内钩住一个事件.很好,对吧?错了,.live()方法非常慢..live()方法实际上将其事件挂钩到文档对象,这意味着事件必须从生成事件的元素冒泡出来,直到到达文档.这可能非常耗时.

它现在已被弃用.jQuery团队中的人员不再推荐使用它,我也不再推荐使用它.尽管挂接和取消挂接事件可能很繁琐,但是没有.live()方法的代码会比使用.live()方法快得多.

您应该使用102而不是101.102大约比.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.但在你对它做任何事情之前,我建议你删除它的101通知系统(每个"更改页面"将通过停止应用程序向你显示这些数据),并将其更改为102功能.

基本上,这个脚本会记录你所有的页面事件,如果你仔细阅读本文(页面事件描述),你就会知道jQm在页面增强、页面转换上花费了多少时间....

最后的笔记

总是,我的意思是,总是阅读官方的jQuery Mobile文档.它通常会为您提供所需的信息,而且与其他一些文档不同的是,这个文档相当不错,有足够的解释和代码示例.

更改:

  • 2013年1月30日——增加了一种预防多事件触发的新方法
  • 2013年1月31日——为第页面转换之间的数据/参数操作章增加了更好的澄清
  • 2013年2月3日——在第页面转换之间的数据/参数操作章中添加了新内容/示例
  • 2013年5月22日-添加了页面转换/更改预防解决方案,并添加了指向官方页面事件API文档的链接
  • 2013年5月18日-针对多事件绑定添加了另一个解决方案

Javascript相关问答推荐

CSS背景过滤器忽略转换持续时间(ReactJS)

使用Apps Script缩短谷歌表中的URL?

使用CDO时如何将Vue组件存储在html之外?

ReactJS中的material UI自动完成类别

对象和数字减法会抵消浏览器js中的数字

调用removeEvents不起作用

通过嵌套模型对象进行Mongoose搜索

Angular material 拖放堆叠的牌副,悬停时自动展开&

如何使覆盖div与可水平滚动的父div相关?

为什么!逗号和空格不会作为输出返回,如果它在参数上?

如何添加绘图条形图图例单击角形事件

如何在Angular17 APP中全局设置AXIOS

在运行时使用Next JS App Router在服务器组件中运行自定义函数

如何在Svelte中从一个codec函数中调用error()?

如何在Angular拖放组件中同步数组?

如何使用TypeScrip设置唯一属性?

是否可以将异步调用与useState(UnctionName)一起使用

如何使本地html页面在重新加载时保持当前可隐藏部分的打开状态?

更改agGRID/Reaction中的单元格格式

我为什么要使用回调而不是等待?