Knockout JS与Ratchet和push.js很好地配合,直到我添加数据转换

我正在使用Ratchet.js / push.js库来创建移动Web应用程序的UI。 在此库中,通过将要加载的文件“推送”到“.content”DOM元素而不是加载整个页面来处理链接。 但是,push.js不会加载它在加载页面时找到的任何脚本 – 这会禁用我的Knockout.js代码。

我在StackOverflow上找到了一个非常好的解决方案 – 只需为push事件添加一个事件监听器。 我对它进行了修改,以便它可以在多个页面上加载任何脚本,因此它可以与外部脚本文件一起使用:

window.addEventListener('push', function () { var scriptsList = document.querySelectorAll('script.js-custom'); // Add a "js-custom" class to your script tag for (var i = 0; i < scriptsList.length; ++i) { // Handle scripts in separate files by assigning the script file name to its id. // We save it in a variable because the ".done" callback is asynchronous. scriptName = scriptsList[i].id; // IMPORTANT: Only one loadable script per page! $.getScript("/path info here/" + scriptName) .done(function (script, textStatus) { eval(script); }) ... error handling ... } }); 

在目标HTML页面中,脚本被赋予class和id标签,因此它们可以使用上述内容:

   

请注意,Knockout绑定必须发生在特定的命名DOM元素中,以便敲除不会混淆:

 ko.cleanNode($("#ChallengePage")[0]); ko.applyBindings(challengeFn, $("#ChallengePage")[0]); 

我们使用cleanNode来避免“已经绑定”的错误。

好! 所以这一切都很有效,我希望有人在努力解决这个问题。

但是,当链接被赋予过渡时:

 .... 

然后它打破了“无法读取属性’nodeType’的undefined。我原以为可能只是等待转换完成的问题,但即使我用以下内容替换脚本的eval:

 scriptContents = script; setTimeout(function () { eval(scriptContents); }, 1000); 

它没有帮助。

任何建议或协助将不胜感激! 如果我不使用过渡,我真的不需要“推”页面,所以我希望有人能有最后一把钥匙让这一切都有效!

更新:发生错误是因为使用转换时“document.querySelectorAll”调用使用当前文档而不是正在推送的文档。 此外,使用“webkitTransitionEnd”作为我的事件也可以,但这不能解决文档问题。 因此,我可以完成这项工作,但仅限于一次转换 – 现在我没有办法让文档被加载。 理想情况下,无论链接是否使用转换,解决方案都是我正在寻找的解决方案。

Ratchet和Knockout的组合在未来几个月可能会很受欢迎,所以我希望其他人能找到这个解决方案。

要结合Ratchet.js和Knockout.js库,只需要处理Ratchet.js(通过Push.js)将尝试管理页面转换的事实。 在转换过程中,目标页面上的JavaScript(包括Knockout)将不会运行,除非您明确指出这一点。 这就是这个解决方案的作用:即使Ratchet正在管理页面转换,它也可以加载和运行你的Knockout JavaScript代码。

在我的解决方案中,我们始终将JavaScript放在单独的文件中,并实现内容安全策略,禁止在页面上运行任何JS代码。 它只是良好的安全卫生,有助于减少XSS攻击的攻击面。 因此,下面的解决方案1)假设JS在一个单独的文件中,并且2)假设HTML和JS文件具有完全相同的名称和路径 – 除了扩展(类似于将.js文件视为ASP)。 HTML文件的.NET代码隐藏)。

在“根”页面上 – 启动与移动网络应用上其他网页的所有互动的网页,放置以下function。 每当Ratchet加载相应的.html文件时,它都会加载相应的.js文件:

 window.addEventListener('push', function (params) { var targetPage = params.target.document.baseURI.replace(".html", ".js"); $.getScript(targetPage) .done(function (script, textStatus) { eval(script); }) .fail(function (jqxhr, settings, exception) { alert("Error loading script: " + exception); }); }); 

请注意,您必须将Knockout绑定应用于HTML页面中的命名且唯一的div(通常是直接位于Ratchet .content div下方的div)。 这只是因为每个页面加载必须将其Knockout绑定仅应用于正在加载的HTML。

 ko.cleanNode($("#DivPageName")[0]); ko.applyBindings(KnockoutFn, $("#DivPageName")[0]); 

更新:我发现,当从历史堆栈中推送和弹出页面时,此解决方案有时会“混淆”。 我决定不使用它,虽然看起来它有97%左右。 如果有人有任何改进可以使这完全可靠,我全都耳朵!