20

我有一个使用 jquery-mobile (jqm) 和淘汰赛构建的移动单页 Web 应用程序。应用程序本身有多个页面,但它们都包含在一个 HTML 文档中。

问题:在将我的“为页面创建视图模型”从同步行为更改为异步行为之后,我遇到了 jquery-mobile 在数据准备好之前触发其事件的问题。

背景:直到最近,我一直在处理示例数据,基本上是一个巨大的 JSON blob,一切都很顺利。使用来自各种来源的视图模型的新异步组合,数据不会立即准备好,我的“buildViewModel”方法需要一个延续回调,而不是仅仅同步返回数据。

我正在订阅 pagebeforecreate 和 pagebeforechange 事件,并触发代码以在此处填充视图模型。问题是,从事件处理程序返回后,jqm 在数据可用之前触发剩余的事件链。这会导致页面转换到未准备好的页面,这是不希望的。

event.preventDefault一旦页面准备好a)增强和b)页面转换发生,我尝试调用所有之前的事件并手动调用 $.mobile.changePage ,但没​​有任何运气。

我已经扫描了 jquery-mobile 源,但没有发现任何看起来可以让我延迟pagebeforeshow事件的东西,这基本上是我能够正确呈现页面所需要的。

在 jquery-mobile 尝试增强页面之前以及在执行到页面的过渡之前,如何确保 1) 数据可用和 2) 已应用敲除以执行初始 DOM 操作?

我还考虑过使用同步 ajax 来获取资源,但这(我认为)不适用于从设备加载的资源(使用 PhoneGap/Cordova),并且会产生其他我想避免的负面后果。

FWIW,我想避免通过在各处连接点击处理程序来手动处理所有导航事件,但如果需要,我对所有解决方案持开放态度。

抱歉,如果这是重复的;我搜索并阅读了大量问题,但没有找到完全相同的答案或问题。我会是第一个遇到这个问题的人,这听起来令人难以置信,因为我想这是一个常见的场景。

更新:澄清问题场景描述。

4

6 回答 6

13

我有这个完全相同的问题。

我能想出的唯一解决方案是编写一个自定义转换处理程序,该处理程序将延迟启动转换,直到 Ajax 请求完成。

这是一个展示该技术的小提琴。小提琴不使用淘汰赛,但确实展示了如何推迟过渡。

基本上,由于$.ajax()返回了一个 Promise,我可以将它通过管道传递到默认转换处理程序返回的 Promise 中,并从我的新处理程序中返回它。

在我的 pagebeforeshow 处理程序中,我将 Ajax 承诺附加到页面,以便转换处理程序可以访问它。不确定这是否是最好的方法,但我比使用全局变量更喜欢它。

我唯一不喜欢的是它延迟了转换的开始,直到 Ajax 响应到达,所以感觉页面已经“挂起”给用户,让他们再次点击。手动显示加载消息会让人感觉更灵敏一些。

希望这会有所帮助,如果您找到更好的解决方案,请告诉我!

于 2012-12-31T00:52:34.160 回答
5

在 jQuery Mobile 中面对动态内容时,延迟到新页面的转换直到其内容准备好是一个非常常见的问题。解决这个问题最方便的方法是:

  • 不是经典的 href 类型导航,而是基于“单击”操作的链接,该操作将首先检索内容,在 DOM 中构建一个新页面,然后通过$.mobile.changePage. 这种方式的优点是容易到位,缺点是不用经典href链接导航

  • 在文档级别绑定pagebeforechange事件以检测导航时目标页面是否是您的页面之一,该页面应包含动态内容。在这种情况下,您可以防止发生默认导航,花时间生成页面,并在成功时进行转换。这在动态注入内容的 JQM 文档中有所描述。优点是您仍然可以依赖标准href链接导航,但它需要更多代码和上游设计才能正确检测和操作页面导航。

    $(document).on( "pagebeforechange", function( e, data ) {
        if ( typeof data.toPage === "string" ) {
             if ( data.toPage === "myDynamicPageName" ) {
                 e.preventDefault(); //used to stop transition to the page (for now)
    
                 /*
                    Here you can make your ajax call
                    In you callback, once you have generated the page you can call
                    $.mobile.changePage
                    (you can pass the Div of the new page instead of its name as
                    the changepage parameter to avoid interrupting again the page change) 
                 */
              }
          }
    });
    
于 2013-01-02T09:04:15.070 回答
3

将您的链接设置为调用“加载”函数而不是进行页面转换。在您的加载函数中,显示“加载消息”并进行 JSON 调用。最后,在 JSON 回调函数中,将page更改为page2

加载函数:

function loadPage2() {
    /* show wait page */
    $.mobile.loading( 'show', {
            text: 'Loading massively huge dataset',
            textVisible: true
    });

     /* perform JSON call then call callback */
 }

回调函数

function callback() {
    $.mobile.changePage("#page2");
}

这是一个有效的 JSFiddle:http: //jsfiddle.net/8w7PM/

请注意,如果您不希望用户在等待时能够更新页面 1 中的输入字段,请在页面 1 和页面 2 之间引入“等待页面”,“等待页面”的 init 与“loadPage2”相同.

于 2013-01-04T00:31:59.750 回答
0

我有一个小型 jQuery Mobile / KnockoutJS 应用程序,并且遇到了同样的问题。我的应用程序包含大约 5 页。所有内容都包含在单个物理 HTML 文档中,标准<div data-role="page">标记分隔各个页面。

$.mobile.changePage()由于成功,我最终选择了基于点击的导航并开火$.ajax

onclick这种技术的一个缺点是,当依赖于vshref属性时,您将失去按钮突出显示。请参阅我的相关帖子:href vs scripted page transitions and button highlighting

后来我选择同时提供两者并依靠href来执行导航,同时使用onclick调用我的 JavaScript 逻辑来加载 ViewModel 等。我发现这是一个问题的唯一地方是源页面上可能需要验证时。如果失败,则过渡已经开始,然后 UI 会闪回到源页面。丑陋但这只发生在我的应用程序中的有限实例中。

我认为这些都不是 Knockout 特有的。我的确切解决方案可能会给您带来问题,因为您的导航可能在您的模型完全加载之前完成,但如果您依赖$.mobile.changePage(),它应该都可以工作并隐藏您的页面,直到它加载之后。过渡应该可以正常工作。

<a href="#MyNewPage" data-bind="click:LoadNewPage" data-role="button">
    Load Page
</a>

$.ajax({
    url: url,
    cache: false,
    dataType: "json",
    data: requestData,
    type: "POST",
    async: true,
    timeout: 10000,
    success: function (data, textStatus, jqXHR) {
        // use either href or changePage but not both
        $.mobile.changePage("#NewPage");
    },
    error: function (jqXHR, textStatus, errorThrown) {
        alert("AJAX Error. Status: " + textStatus);
        // jqXHR.status
        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    }
});
于 2012-12-31T19:01:18.840 回答
0

我认为您必须为所有要绑定响应数据的小部件再次触发

例如,您必须为元素调用triggerwithcreaterefrest事件 $("#element").trigger('create'); JQuery Mobile 会将所有默认事件按原样绑定到元素

- - 编辑 - -

我刚刚创建了一个示例代码,我认为这与您的问题相同,请尝试链接http://jsfiddle.net/ndkhoiits/BneqW/embedded/result/

在渲染数据之前,我们必须调用服务来让它们显示,这就是为什么所有被 jqm 绑定的事件都会被删除。

我有一个解决方法,不要让jqm在元素上触发任何东西,我们会在所有数据被knockoutjs绑定后触发它让我们试试固定版本 http://jsfiddle.net/ndkhoiits/c5a2b/embedded/result /

这是代码http://jsfiddle.net/ndkhoiits/c5a2b/

于 2012-12-28T15:56:53.280 回答
-2

您应该将页面转换的代码放在 AJAX 调用的成功函数中。

$.ajax({
    url:"request-url",
    data: data,
    type: "POST",
    success: function(response){
        // Add Transition Code Here
    }  
});
于 2012-12-28T18:10:46.290 回答