在 jQueryMobile 中未触发 jQuery 单击事件

Posted

技术标签:

【中文标题】在 jQueryMobile 中未触发 jQuery 单击事件【英文标题】:jQuery click event not firing in jQueryMobile 【发布时间】:2013-04-28 20:44:40 【问题描述】:

使用 jQuery jquery-1.9.1.js 和 jQueryMobile 1.3.1 (Chrome 26/Windows 7) 我不明白为什么绑定到 #one1 的这些“点击”事件之一会触发而另一个不会:

html

<div data-role="page" id="one" data-theme="a">
    <div data-role="header" data-position="inline">
        <h1>One</h1>
    </div>
    <div data-role="content" data-theme="a">
        <a href="#" id="one1">[one]</a>
        <a href="#two">two</a>
        <a href="#three">three</a>
    </div>
</div>

javascript

<script>
$(document).on( "mobileinit", function() 
    $(document).on('click', '#one1', function(e)
        console.log('firing');
    );
    $('#one1').on("click", function() 
        console.log('not firing');
    );
); 
</script>

当我在 JSFiddle 中运行它时,两个事件都会在未包含在“mobileinit”事件中时触发: http://jsfiddle.net/9NRwa/

我在这里错过了什么?

【问题讨论】:

移除mobileinit事件,这里不打算使用。它用于设置全局默认值,应该放在头部,在 jQuery 之后和 jQuery 移动脚本之前。当您的脚本包含在文档中时,请使用 $('.selector').on 当您的脚本位于单独的 js 文件中时,请使用 $(document).on(event,'.selector' 【参考方案1】:

简介

首先,mobileinit 事件不应该用于事件绑定。虽然它可以像那样使用 mobileinit 不是为此目的而创建的。它是为 jQuery Mobile 参数自动初始化而创建的,因此不应用于事件绑定。

正确的方法是使用正确的页面事件,例如 pageinit。有关页面事件的更多信息,请查看我的其他答案,其中涵盖各种 jQuery Mobile 页面事件及其与通常的 jQuery 文档就绪范例的区别:jQuery Mobile: document ready vs page events

不要让我回答这个问题。像点击这样的事件可以通过几种不同的方式进行绑定。 让我们看看你使用过的例子:

jQuery 的各种事件绑定方式

第一个例子

$(document).on('click', '#one1', function(e)
    console.log('firing');
);

第一个示例是新的东西,首先使用现在已弃用的方法 live。 基本上,它是一种事件委托机制,允许您不仅将事件处理程序绑定到给定节点类型的所有现有实例,而且还绑定到给定节点类型的任何未来实例(“类型”是指一组 DOM 节点匹配给定的 jQuery 选择器)。我在这里想说的是,在事件绑定期间,该元素不需要存在于 DOM 中,基本上这种方法通过将事件处理程序绑定到文档本身,然后对通过 DOM 冒泡的所有事件作出反应。因此,在事件绑定期间元素 #one1 是否存在并不重要。您可以稍后动态创建它,它仍然可以工作。

第二个例子

$('#one1').on("click", function() 
    console.log('not firing');
);

这是旧的事件绑定方式。它要求事件在绑定事件之前存在于 DOM 中。在您的情况下,您试图将此单击事件绑定到当时 DOM 中不存在的元素。在绑定过程之后加载它并不重要。

工作示例

jsFiddle 示例:http://jsfiddle.net/Gajotres/QmNsa/

看看这个例子。在那里你会看到 jQuery Mobile 中 5 种不同的点击事件绑定方式:

2点击事件绑定在HEAD中,在页面初始化到DOM之前 在pagebeforeshow事件的HEAD中绑定了2个点击事件,基本上这也是绑定的委托,因为事件是在页面即将显示并且已经在DOM中时绑定的 1 个点击事件在所有页面内容之后绑定在一个 BODY 中。因为此时所有内容都加载到 DOM 中,所以这个点击事件会起作用。

HTML:

<!DOCTYPE html>
<html>
    <head>
        <title>jQM Complex Demo</title>
        <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
        <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>    
        <script>
                $(document).on('click', '#one1', function(e)
                    // This example will work because it was bind with event delegation process
                    console.log('Firing 1');
                );
                $('#one1').on("click", function() 
                    // This example will not work because event do not exist in this moment
                    console.log('Not firing');
                );
                $(document).on( "pagebeforeshow", function() 
                    // This example will work because it was bind with event delegation process            
                    $(document).on('click', '#one1', function(e)
                        console.log('Firing 2');
                    );
                    // This example will work because element exist in a DOM during the pagebeforeshow event
                    $('#one1').on("click", function() 
                        console.log('Firing 3');
                    );
                );             
        </script>
    </head>
    <body>
        <div data-role="page" id="index">
            <div data-theme="b" data-role="header">
                <h1>Index page</h1>
            </div>

            <div data-role="content">
                <a href="#" id="one1" data-role="button">[one]</a>
            </div>
        </div>    
        <script>
            $('#one1').on("click", function() 
                // This example will  work because we are binding it when element is already loaded into the DOM
                console.log('Firing 4');
            );            
        </script>
    </body>
</html>   

结论

不要使用 mobileinit 事件进行事件绑定,它会在页面加载到 DOM 之前触发,并且只有通过委托绑定的事件才会起作用。 在正确的 jQuery Mobile 页面中绑定您的事件events

有关此主题的有用链接:

    jQuery Live() Method And Event Bubbling

    虽然 live 方法已被弃用,但应使用 on 方法。在某些基准测试中,方法的速度要快 2 倍。

    jQuery Mobile: document ready vs page events

    Various jQuery Mobile page events What does “event bubbling” mean?

【讨论】:

【参考方案2】:

作为docs stated:

因为 mobileinit 事件会立即触发,所以您需要 在加载 jQuery Mobile 之前绑定您的事件处理程序

目前,您的 mobileinit 事件在 jQuery Mobile 加载后运行,因为 jsFiddle 将在完成加载您从侧边栏中选择的任何库后执行您的 javascript 代码。为了使其正常工作,您的结构应如下所示:

<script src="jQuery library include first"></script>
<script>
    $(document).on("mobileinit", function() 
        // Your code here
    );
</script>
<script src="jQuery Mobile include last"></script> 

【讨论】:

您的代码 sn-p 正是我所拥有的。我一直认为 mobile init 是 onload 的等价物——错了!

以上是关于在 jQueryMobile 中未触发 jQuery 单击事件的主要内容,如果未能解决你的问题,请参考以下文章

在 jQuery mobile 中未选择选项卡时禁用表单输入

文档 pageinit 在 iOS (jQueryMobile) 上多次触发

如何在 jqueryMobile 中正确创建类似于 iOS tabbarController 的 tabbar 控制器?

在 Android 手机中未触发 keyPress 事件

引导输入掩码无法工作,控制台中未显示错误

Cordova 设备在 iOS 中未触发