Knockout JS在Ratchet和push.js中很好地工作,直到我添加数据转换 [英] Knockout JS plays nicely with Ratchet and push.js until I add a data-transition

查看:89
本文介绍了Knockout JS在Ratchet和push.js中很好地工作,直到我添加数据转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Ratchet.js / push.js库为移动网络应用创建用户界面。在这个库中,通过将待加载文件推送到.contentDOM元素中而不是加载整个页面来处理链接。但是,push.js不会加载它在加载页面时找到的任何脚本 - 这会禁用我的Knockout.js代码。

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

  window.addEventListener( 'push',function(){
var scriptsList = document.querySelectorAll('script.js-custom'); //在您的脚本标记中添加一个js-custom类
for(var i = 0; i< scriptsList.length; ++ i){
//通过将脚本文件名赋给它的id来处理单独文件中的脚本
//我们将它保存在一个变量中,因为.done回调是异步的
scriptName = scriptsList [i] .id; //重要提示:每页只有一个可加载的脚本!
$ .getScript(/ path info here /+ scriptName)
.done(function(script,textStatus){
eval(script);
})
...错误处理...
}
});

在目标HTML页面中,脚本被赋予class和id标签,以便它们可以与上面的一样:

 < script src =Challenge.jsclass =js-customid =challenge.js><<< ; /脚本> 

请注意,Knockout绑定必须发生在特定的命名DOM元素上, t
$ b

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

我们使用cleanNode来避免已绑定的错误。 b $ b

OK!所以这一切都很好,我希望有人在这个问题上有所作为。

然而,当链接被转换时:




$ b

 < a href =challenge.htmldata-transition =slide-in> .... 

然后它打破了Can not read property'nodeType'undefined。我原以为这可能只是一个等待的问题转换完成,但即使我用脚本代替eval:

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

没有帮助。



任何建议或协助将不胜感激!如果我不使用转换,我并不需要推页面,所以我希望有人会有最后一把钥匙,使这一切工作!



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

Ratchet的组合Knockout可能会在未来几个月流行,所以我希望其他人能够找到这个解决方案。



结合Ratchet.js和Knockout.js库只需要处理Ratchet.js(通过Push.js)将尝试管理你的页面转换。在转换过程中,除非您专门做到这一点,否则目标页面上的JavaScript(包括Knockout)将不会运行。这就是这个解决方案的作用:即使Ratchet正在管理页面转换,它也可以加载和运行Knockout JavaScript代码。在我的解决方案中,我们 始终将JavaScript放置在单独的文件中,并实施内容安全策略,禁止在页面上运行任何JS代码。这只是良好的安全卫生,并有助于减少XSS攻击的攻击面。所以下面的解决方案1)假定JS是在一个单独的文件中,并且2)假设HTML和JS文件具有完全相同的名称和路径 - 除了扩展名(有点像将ASP处理为.js文件那样。 NET代码隐藏在HTML文件中)。



在您的根页面 - 启动您与移动网络应用程序中其他页面的所有交互,以下功能。它会在Ratchet加载相应的.html文件时加载相应的.js文件:

pre $ window.addEventListener('push' ,function(params){
var targetPage = params.target.document.baseURI.replace(。html,.js);
$ .getScript(targetPage)
.done (函数(脚本,textStatus){
eval(脚本);
})
.fail(函数(jqxhr,设置,异常){
alert(Error loading script: +例外);
});
});

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

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

更新:我发现这个解决方案有时会因为页面被推入并弹出历史堆栈。我决定不使用它,虽然它似乎在那里约为97%。如果任何人有任何改进,这将使这完全可靠,我都耳朵!


I am using the Ratchet.js/push.js library to create the UI for a mobile web app. In this library, links are handled by "pushing" the to-be-loaded file into the ".content" DOM element rather than loading the entire page. However, push.js does not load any scripts it finds when loading a page - which disables my Knockout.js code.

I found a solution here on StackOverflow that works pretty well - just add an event listener for the push event. I modified it so that it can load any script across multiple pages and so it works with external script files:

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 ...
  }
});

In the target HTML page, scripts are given class and id tags so they work with the above:

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

Note, too, that Knockout bindings have to occur to a specific named DOM element so that knockout doesn't get confused:

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

We use cleanNode to avoid the "already bound" errors.

OK! So all this works great and I hope that someone who is struggling with this finds it useful.

HOWEVER, when the link is given a transition:

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

Then it breaks with a "Cannot read property 'nodeType' of undefined. I had thought that maybe it was just a problem of waiting for the transition to finish, but even if I replace the eval of the script with:

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

it doesn't help.

Any advice or assistance would be greatly appreciated! I don't really need to "push" pages if I don't get to use the transitions so I am hoping that someone will have the last key to making this all work!

UPDATE: The error was occurring because the "document.querySelectorAll" call when using a transition uses the current document rather than the document being pushed. Also, using "webkitTransitionEnd" as my event works as well but this doesn't fix the document issue. Thus, I can make this work, but only for a single transition - now I don't have a way of getting the document being loaded. Ideally, a solution that works whether a links uses a transition or not is what I am looking for.

解决方案

The combination of Ratchet and Knockout will likely be popular in the coming months so I hope that others find this solution.

To combine the Ratchet.js and Knockout.js libraries requires only that you handle the fact that Ratchet.js (via Push.js) will attempt to manage your page transitions. During a transition, the JavaScript on your target page - including Knockout - will not be run unless you specifically make this happen. That is what this solution does: it makes it possible to load and run your Knockout JavaScript code even though Ratchet is managing page transitions.

In my solution, we always place JavaScript in a separate file and implement Content Security Policy that forbids any JS code from running on the page. It is simply good security hygiene and helps reduce the attack surface for XSS attacks. So the solution below 1) assumes that the JS is in a separate file and 2) assumes that the HTML and JS files have the exact same name and path - except for the extensions (sort of like treating the .js file like an ASP.NET code-behind for the HTML file).

On your "root" page - the one that starts all of your interactions with other pages on your mobile web app, place the following function. It will load the appropriate .js file whenever the corresponding .html file is loaded by Ratchet:

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);
        });
});

Note that you will have to apply your Knockout bindings to a named and unique div in your HTML page (generally a div that lives directly underneath the Ratchet .content div). This is just because each page load has to apply its Knockout bindings to just the HTML being loaded.

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

UPDATE: I have found that this solution gets "confused" at times as pages are pushed and popped from the history stack. I have decided not to use it although it seems like it is about 97% there. If anyone has any improvements that would make this completely reliable, I am all ears!

这篇关于Knockout JS在Ratchet和push.js中很好地工作,直到我添加数据转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆