我有一个使用jquery-mobile(jqm)和knockout构建的移动单页Web应用程序。应用程序本身有多个页面,但它们都包含在一个HTML文档中。
问题:在将“创建页面视图模型”从同步更改为异步行为后,我遇到了jquery-mobile在数据准备好之前触发其事件的问题。
背景:直到最近,我一直在处理样本数据,基本上是一个巨大的JSON blob,一切顺利。使用来自各种来源的视图模型的新异步组合,数据不会立即就绪,我的“buildViewModel”方法采用延续回调而不是仅仅同步返回数据。
我正在订阅pagebeforecreate和pagebeforechange事件,并在此处触发代码以填充viewmodel。问题是从事件处理程序返回后,jqm在数据可用之前触发剩余的事件链。这会导致页面转换为未准备好的页面,这是不可取的。
我试图在所有事件前调用event.preventDefault
并在页面准备好a)增强后手动调用$ .mobile.changePage并且b)页面转换发生,但没有任何运气。
我已经扫描了jquery-mobile源,但无法发现任何看起来像是允许我延迟pagebeforeshow
事件的事情,这基本上是我需要的,以便能够渲染页面正确。
在jquery-mobile尝试增强页面之前和执行转换到页面之前,如何确保1)数据可用并且2)已应用knockout来执行初始DOM操作?
我还考虑使用同步ajax来获取资源,但这(我认为)不适用于从设备加载的资源(使用PhoneGap / Cordova),并且还有其他我想避免的负面后果。
FWIW,我想通过在任何地方连接点击处理程序来避免手动处理所有导航事件,但如果需要,我会对所有解决方案持开放态度。
如果这是重复的道歉;我搜索并阅读了大量问题,但没有找到完全相同的答案或问题。我觉得我是第一个遇到这个问题的人听起来很不可思议,因为我认为这是一种常见的情况。
更新:澄清了问题情景说明。
答案 0 :(得分:13)
我有同样的问题。
我能够提出的唯一解决方案是编写一个custom transition handler,推迟启动转换,直到Ajax请求完成。
这是显示该技术的fiddle。小提琴不使用Knockout,但确实显示了如何推迟过渡。
基本上,由于$.ajax()
返回一个promise,我可以将它传递给默认转换处理程序返回的promise,并从我的新处理程序返回它。
在我的pagebeforeshow处理程序中,我将Ajax承诺附加到页面,以便转换处理程序可以访问它。不确定这是否是最佳方式,但我比使用全局变量更喜欢它。
我唯一不喜欢的是它延迟了转换的开始,直到Ajax响应到来,因此它可能感觉页面已经“挂起”给用户再次点击它们。手动显示加载消息会使其感觉更敏感。
希望这有帮助,如果您找到更好的解决方案,请告诉我们!
答案 1 :(得分:5)
在面向jQuery Mobile中的动态内容时,延迟转换到新页面直到其内容准备就绪是一个非常常见的问题。解决这个问题最方便的方法是:
取代传统的href类型导航,将链接基于“点击”操作,这些操作将首先检索内容,在DOM中构建新页面,然后通过{{1}启动到此新页面的转换}。这种方法的优点是易于实施,缺点是您不能使用经典的$.mobile.changePage
链接进行导航
在文档级别绑定href
事件,以检测导航时目标网页是否是应包含动态内容的网页之一。在这种情况下,您可以阻止默认导航发生,花时间生成页面,并在成功时进行转换。这在JQM文档on dynamically injected content中有所描述。优点是您仍然可以依赖标准pagebeforechange
链接导航,但它需要更多的代码和上游设计才能正确检测并对页面导航进行操作。
href
答案 2 :(得分:3)
设置您的链接以调用“加载”功能,而不是进行页面转换。在您的加载函数中,显示“加载消息”并进行JSON调用。最后,在JSON回调函数中,将页面更改为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”。
答案 3 :(得分:0)
我认为您必须再次触发要将响应数据绑定到
的所有窗口小部件例如,您必须使用trigger
或create
事件为元素调用refrest
$("#element").trigger('create');
JQuery Mobile将所有默认事件绑定到元素
---编辑---
我刚刚创建了示例代码,我认为这与您的问题相同,请尝试链接http://jsfiddle.net/ndkhoiits/BneqW/embedded/result/
在重新发送数据之前,我们必须调用服务来显示它们,这就是为什么所有被jqm绑定的事件都将被删除。
我有一个解决方法,不要让jqm触发元素上的任何内容,我们将在所有数据被knockoutjs绑定后触发它 试试修复版 http://jsfiddle.net/ndkhoiits/c5a2b/embedded/result/
答案 4 :(得分:0)
我有一个小的jQuery Mobile / KnockoutJS应用程序,并且一直在努力解决同样的问题。我的应用程序包含大约5页。所有这些都包含在单个物理HTML文档中,标准<div data-role="page">
标记将各个页面分开。
由于$.mobile.changePage()
成功,我终于使用基于点击的导航并点击了$.ajax
。
此技术的一个缺点是,在依赖onclick
vs href
属性时,您将丢失按钮突出显示。请参阅我的相关帖子:href vs scripted page transitions and button highlighting
我后来选择同时提供这两个并依赖href
来执行导航,同时使用onclick
来调用我的JavaScript逻辑来加载ViewModels等。我发现这是一个唯一的地方问题是源页面上是否需要验证。如果失败,则转换已经开始,然后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
}
});
答案 5 :(得分:-2)
您应该在AJAX调用的成功函数中放置页面转换的代码。
$.ajax({
url:"request-url",
data: data,
type: "POST",
success: function(response){
// Add Transition Code Here
}
});