我有一个使用jquery-mobile (jqm)和knockout构建的移动单页web应用程序。应用程序本身有多个页面,但它们都包含在一个HTML文档中。
问题:改变我的"创建视图模型的页面"从同步到异步行为后,我有问题,jquery-mobile触发它的事件之前,数据准备好了。
背景:直到最近,我一直在处理样本数据,基本上是一个巨大的JSON blob,一切都很顺利。随着来自各种来源的视图模型的新的异步组合,数据不会立即准备好,我的"buildViewModel"方法需要一个延续回调,而不仅仅是同步返回数据。
我订阅了pagebeforecreate和pagebeforechange事件,并启动代码来填充这里的视图模型。问题在于,在从事件处理程序返回之后,jqm会在数据可用之前触发剩余的事件链。这会导致页面转换到未准备的页面,这是不希望看到的。
我已经尝试在所有事件之前调用event.preventDefault
并手动调用$.mobile。changePage一旦页面准备好a)增强和b)发生页面转换,但没有任何运气。
我已经扫描了jquery-mobile源,但是没有发现任何看起来可以让我延迟pagebeforeshow
事件的东西,这基本上是我需要的,以便能够正确渲染页面。
我如何确保1)数据可用,2)在jquery-mobile尝试增强页面之前,以及在执行页面过渡之前,已应用knockout来执行初始DOM操作?
我还考虑使用同步ajax来获取资源,但这将(我认为)不工作的资源从设备加载(使用PhoneGap/Cordova),并有其他的负面后果,我想避免。
fww,我想避免手动处理所有的导航事件通过连接点击处理程序无处不在,但我是开放的所有解决方案,如果需要。
抱歉,如果这是重复的;我搜索并阅读了大量的问题,但没有找到一个完全相同的答案或问题。我是第一个遇到这个问题的人,这听起来令人难以置信,因为我想这是一个常见的场景。
更新:澄清问题场景描述。
我也遇到过同样的问题。
我能想到的唯一解决方案是编写一个自定义转换处理程序,延迟开始转换,直到Ajax请求完成。
这是展示该技术的小提琴。小提琴不使用Knockout,但展示了如何延迟转换。
基本上,由于$.ajax()
返回一个承诺,我可以将其管道到默认转换处理程序返回的承诺中,并从我的新处理程序返回它。
在pagebeforeshow处理程序中,我将Ajax承诺附加到页面上,以便转换处理程序可以访问它。不确定这是否是最好的方法,但我喜欢它比使用全局变量更好。
我唯一不喜欢的是,它延迟了转换的开始,直到Ajax响应到达,所以它可能会让用户感觉页面已经"挂起",让他们再次点击。手动显示加载消息让它感觉更灵敏。
希望这对你有帮助,如果你找到更好的解决方案,请告诉我!
在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) */ } } });
设置你的链接调用"load"函数而不是做页面过渡。在加载函数中,显示"加载消息"并进行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/
注意,如果你不希望用户在等待时能够更新Page 1中的输入字段,那么在Page 1和Page2之间引入一个"wait Page","wait Page"的初始化与"loadPage2"的初始化相同。
我认为你必须再次启动所有你想要绑定数据的小部件从响应到
例如,您必须使用create
或refrest
事件为元素调用trigger
$("#element").trigger('create');
JQuery Mobile会将所有默认事件绑定到元素
—EDIT—
我刚刚创建了一个示例代码,我认为这是相同的你的问题,请尝试链接http://jsfiddle.net/ndkhoiits/BneqW/embedded/result/
在提交数据之前,我们必须调用服务来获取数据以进行显示,这就是为什么jqm绑定的所有事件都将被删除。
我有一个解决办法,不要让jqm在元素上触发任何东西,我们将在所有数据被knockoutjs绑定后触发它让我们试试固定的版本http://jsfiddle.net/ndkhoiits/c5a2b/embedded/result/
这是代码http://jsfiddle.net/ndkhoiits/c5a2b/
我有一个小的jQuery Mobile/KnockoutJS应用程序,并一直在努力解决同样的问题。我的应用程序包含大约5页。所有这些都包含在一个物理HTML文档中,用标准的<div data-role="page">
标记分隔各个页面。
我最终选择了基于点击的导航,并在$.ajax
成功后启动了$.mobile.changePage()
。
该技术的一个缺点是,当依赖onclick
和href
属性时,您将失去按钮高亮显示。参见我的相关文章:href vs脚本页面转换和按钮突出显示
我后来选择提供并依靠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
}
});
您应该将页面转换的代码放置在AJAX调用的成功函数中。
$.ajax({
url:"request-url",
data: data,
type: "POST",
success: function(response){
// Add Transition Code Here
}
});