浏览 12636 次
锁定老帖子 主题:prototype.js类库的一点缺陷。
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-09-16
这几天用到prototyp的Ajax.Updater()方法来动态更新页面上的div块,发现一个问题。比如我需要在当前页面Index.aspx中id为content的div替换成另外一个页面Content.aspx,那么我可以使用方法new Ajax.Updater("content", "Content.aspx")来实现,很快捷,不过这里就出现问题了,假设Content.aspx页面的内容如下: Content.aspx <html> ..... <script type="text/javascript"> function myFunc() { ...... } </script> <body> <div onclick="myFunc()">click me </div> </body> ........... Index.aspx的代码如下: Index.aspx <html> ... <script type="text/javascript" src="prototype.js"></script> <body> <div id="content"> </div> <script language="javascripot"> new Ajax.Updater("content", "Content.aspx"); </script> </body> </html> 页面content.aspx的内容确实能够正确无误的出现在Index.aspx中的div内部,可惜的是我们定义在Content.aspx中的js 函数确实无法被触发了。为啥?因为在Index.aspx的js上下文中根本不存在这样的一个函数。Oh,别急,prototype的这个方法提供了多个参数选项。有一个就是evalScript:true/false 的参数。看来就是是否执行js代码了。加上去再说吧。加上去以后的Index.aspx代码如下: Index.aspx <html> ... <script type="text/javascript" src="prototype.js"></script> <body> <div id="content"> </div> <script language="javascripot"> new Ajax.Updater("content", "Content.aspx", {evalScripts:true}); </script> </body> </html> 再试试看?God,照样不行,还是那句话,myFunc还是不在当前Index页面的上下文中。仔细看看代码,myFunc是在Content.aspx页面中定义的,所以咋们需要换一个定义的方式, Content.aspx <html> ..... <script type="text/javascript"> myFunc = function() { ...... } </script> <body> <div onclick="myFunc()">click me </div> </body> ........... 这下可以了吧。为什么?function XX是声名一个函数。但是XX = function 则是隐含的生命了一个函数,这样在Index中就可以访问此函数了。嘿嘿,问题解决了吧?happy了吧?这个时候,发现Content.aspx中就那么一个小小的函数不够我用,咱使还需要使用其他的js类myclass.js。恩。这个时候Content.aspx代码如下,同时附上 myclass.js代码: Content.aspx <html> <script type="text/javascript" src="myclass.js"></script> ..... <script type="text/javascript"> myFunc = function() { myclass.func(); } </script> <body> <div onclick="myFunc()">click me </div> </body> ........... myclass.js var myclass = new Object(); myclass.func() { alert("func"); } 这个时候你会发现又不行了,js说找不到myclass的定义。头疼吧。。得了,这回prototype 也没设啥参数再让你来设置了,咱还是去看看它代码吧,看看关键的地方:(提示一下,俺是1.40版本的) 先奔主题吧,找到Ajax.Updater()的定义 Ajax.Updater = Class.create(); Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { initialize: function(container, url, options) { this.containers = { success: container.success ? $(container.success) : $(container), failure: container.failure ? $(container.failure) : (container.success ? null : $(container)) } this.transport = Ajax.getTransport(); this.setOptions(options); var onComplete = this.options.onComplete || Prototype.emptyFunction; this.options.onComplete = (function(transport, object) { [b]this.updateContent();[/b] <------ 这里调用更新div内容。往下看。 onComplete(transport, object); }).bind(this); this.request(url); }, updateContent: function() { var receiver = this.responseIsSuccess() ? this.containers.success : this.containers.failure; var response = this.transport.responseText; [b]if (!this.options.evalScripts) [/b] <----哦,如果没设置evalScripts = true 就清空script代码 { response = response.stripScripts(); } if (receiver) { if (this.options.insertion) { new this.options.insertion(receiver, response); } else { [b]Element.update(receiver, response); [/b]<----这里调用prototype扩展的Element.update函数,看下面。 } } if (this.responseIsSuccess()) { if (this.onComplete) setTimeout(this.onComplete.bind(this), 10); } } }); Element.udpater 函数的定义: update: function(element, html) { [b]$(element).innerHTML = html.stripScripts();[/b] <----先把清除掉js代码的html内容加入到elemtn中。(就是你需要更新的div) setTimeout(function() {html.evalScripts()}, 10); <----然后调用html内容中的js代码。 }, String.evalScripts 函数的定义: evalScripts: function() { [b]//==========edit by foxty 粗线是我加的,先看它原来的定义,最后一句。 var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var scripts = this.match(matchAll); var headEle = document.getElementsByTagName("head")[0]; for(var i = 0; scripts && i < scripts.length; i++) { var scriptEle = document.createElement("script"); scriptEle.type = "text/javascript"; var script = scripts[i]; var res = script.match(/src=\"(.*)\"/ig); if(res) { scriptEle.src = RegExp.$1; }else { //scriptEle.innerText = script; } headEle.appendChild(scriptEle); } //alert(headEle.innerHTML); //==========end [/b] return this.extractScripts().map(eval); <----这里可以继续找prototype扩展的String.extractScript函数, 发现里面仅仅是对返回内容的js代码块进行了处理,对于引入的js文件并没有做任何处理,"罪魁祸首"就在这里了。没办法,咱只能 自己动手实现了,所以有了上面一段加粗的代码,把返回的html中关于js文件导入的地方全部重新加入到当前文档中去。记住不能 用简单的innerHTML = "...."来实现,那样没有任何效果,只能在当前文档中createElement("script") 然后append到当前文档中。 }, 好了,现在咱们再重新试试看。终于可以在index .aspx中完好无损的调用本身存在于content.aspx中的js函数了。 结束语:今天为了这个问题花了2个多小时的时间才解决,prototype确实非常实用非常方便,但是这里的处理确不尽人意。或许你会有更好的解决办法。欢迎讨论哈。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-09-17
http://ajax.org/space/start/2006-01-31/1
PS: ajax后加一个cn,不知道Robbin为什么要把ajaxcn替换成ajax |
|
返回顶楼 | |
发表时间:2006-09-17
http://www.iteye.com/post/139822
哦 我明白我这个问题出在哪里了。并非我原先猜想的那样,只是新生产的javascript代码没有被调用而言 |
|
返回顶楼 | |
发表时间:2006-09-17
zelsa 写道 http://ajax.org/space/start/2006-01-31/1
PS: ajax后加一个cn,不知道Robbin为什么要把ajaxcn替换成ajax 我是说怎么打不开 。prototype.js中的Ajax.Updater()方法确实能调用innerHTML中的js,不过如果innerHTML中是引入其他的js文件就不行了。我所说的就是要完全解决这个问题。 |
|
返回顶楼 | |
发表时间:2007-01-17
我下载的1.4.0里面怎么找不到上述的代码段:
var headEle = document.getElementsByTagName("head")[0]; for(var i = 0; scripts && i < scripts.length; i++) { var scriptEle = document.createElement("script"); scriptEle.type = "text/javascript"; var script = scripts[i]; var res = script.match(/src=\"(.*)\"/ig); if(res) { scriptEle.src = RegExp.$1; }else { //scriptEle.innerText = script; } headEle.appendChild(scriptEle); } //alert(headEle.innerHTML); //==========end </b> return this.extractScripts().map(eval); <----这里可以继续找prototype扩展的String.extractScript函数, ????? 不知道是你的版本有问题还是我的有问题。希望楼主去下载一份最新的源码,再重新试试。 我想在项目中使用prototype,但又没时间去做相关方面的测试。如果最新的js源码还存在此问题的话,请通知我一声。 呵呵,先说谢啦。 |
|
返回顶楼 | |
发表时间:2007-01-17
fujianhua168 写道 我下载的1.4.0里面怎么找不到上述的代码段:
这些代码是我修改后加上去的.本身prototype是没有这段代码的.
var headEle = document.getElementsByTagName("head")[0]; for(var i = 0; scripts && i < scripts.length; i++) { var scriptEle = document.createElement("script"); scriptEle.type = "text/javascript"; var script = scripts[i]; var res = script.match(/src=\"(.*)\"/ig); if(res) { scriptEle.src = RegExp.$1; }else { //scriptEle.innerText = script; } headEle.appendChild(scriptEle); } //alert(headEle.innerHTML); //==========end </b> return this.extractScripts().map(eval); <----这里可以继续找prototype扩展的String.extractScript函数, ????? 不知道是你的版本有问题还是我的有问题。希望楼主去下载一份最新的源码,再重新试试。 我想在项目中使用prototype,但又没时间去做相关方面的测试。如果最新的js源码还存在此问题的话,请通知我一声。 呵呵,先说谢啦。 |
|
返回顶楼 | |
发表时间:2007-01-18
才发现几个月前的帖子又被翻出来了,innerHTML根本就不是标准的用法,只不过所有浏览器都支持。可惜的是各家的实现方式不同。
具体到这个问题,感兴趣的去看看这篇文章,谈的比较细了 http://homepage.scau.edu.cn/club/scauunit/lbs/article.asp?id=167 |
|
返回顶楼 | |