3

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

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

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 来避免“已经绑定”的错误。

好的!所以这一切都很好,我希望为此苦苦挣扎的人会发现它很有用。

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

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

然后它以“无法读取未定义的属性'nodeType'”中断。我曾认为这可能只是等待转换完成的问题,但即使我将脚本的 eval 替换为:

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

它没有帮助。

任何建议或帮助将不胜感激!如果我不使用过渡,我真的不需要“推送”页面,所以我希望有人拥有最后一把钥匙来完成这一切!

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

4

1 回答 1

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。 NET 代码隐藏 HTML 文件)。

在您的“根”页面 - 开始您与移动 Web 应用程序上其他页面的所有交互的那个页面,放置以下函数。只要 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%。如果有人有任何改进可以使它完全可靠,我全神贯注!

于 2014-05-25T22:43:33.840 回答