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

时间:2014-05-25 20:16:19

标签: javascript jquery html ratchet-2 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标签,因此它们可以使用上述内容:

    <script src="Challenge.js" class="js-custom" id="challenge.js"></script>

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

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

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

OK!所以这一切都很有效,我希望那些正在努力解决这个问题的人发现它很有用。

然而,当链接被赋予过渡时:

<a href="challenge.html" data-transition="slide-in">....

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

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

没有帮助。

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

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

1 个答案:

答案 0 :(得分:3)

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代码隐藏)。

在你的&#34; root&#34;页面 - 启动与移动网络应用上其他网页的所有互动的网页,放置以下功能。每当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]);

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