调用从Ajax响应返回的JavaScript函数

我有一个系统,我发送一个Ajax命令,它返回一个脚本块中的一个函数。 在将这些数据正确插入到DIV后,我希望能够调用此函数来执行所需的操作。

这可能吗?

我想正确地解释你的问题在这种forms下:“好的,我已经完成了所有的Ajax的东西,我只是想知道是否JavaScript函数插入到DIV的Ajaxcallback可以在任何时候从这个时刻,也就是说,我不想将其调用callbackcallback“。

好的,如果你的意思是这样的话,答案是肯定的,你可以在浏览器页面持久化期间的任何时候调用你的新代码,在以下情况下:

1)由Ajaxcallback返回的JavaScript代码必须在语法上可以;
2)即使将函数声明插入到现有的<div>元素的<script>块中,浏览器也不会知道新函数是否存在,因为声明代码从未执行过。 所以,你必须eval()由Ajaxcallbackeval()返回的声明代码,以便有效地声明你的新函数,并在整个页面生命周期中使用它。

即使相当虚拟,这个代码解释了这个想法:

 <html> <body> <div id="div1"> </div> <div id="div2"> <input type="button" value="Go!" onclick="go()" /> </div> <script type="text/javascript"> var newsc = '<script id="sc1" type="text/javascript">function go() { alert("GO!") }<\/script>'; var e = document.getElementById('div1'); e.innerHTML = newsc; eval(document.getElementById('sc1').innerHTML); </script> </body> </html> 

我没有使用Ajax,但概念是一样的(即使我select的例子确实不是很聪明:-)

一般来说,我不质疑你的解决scheme的devise,也就是说,在一个单独的.js文件等中外部化+概括function是否合适,但是请注意,这样的解决scheme可能会引发更多的问题,特别是如果你的Ajax调用应该重复,也就是说,如果同一个函数的上下文应该改变,或者在声明的函数持久性应该被关注的情况下,那么也许你应该认真考虑把你的devise改成这个线程中的一个build议的例子。

最后,如果我误解了你的问题,并且当你的Ajaxcallback返回的时候你正在讨论函数的上下文调用,那么我的感觉就是build议krosenvold描述的Prototype方法,因为它是跨浏览器,testing和function齐全的,这可以为您未来的实施提供更好的路线图。

这些都没有为我工作

下面呢!

我花了几个小时find一个解决方法。

在返回的HTML / Ajax / JavaScript文件中,您将拥有一个JavaScript标记。 给它一个ID,像脚本 。 添加一个id到这些标签是不常见的,但是需要专门引用它。

 <script type="text/javascript" id="runscript"> alert("running from main"); </script> 

在主窗口中,通过仅评估JavaScript代码的新块来调用eval函数(在本例中,它被称为runscript ):

 eval(document.getElementById("runscript").innerHTML); 

至less在Internet Explorer 9和Google Chrome中是有效的。

这是完全可能的,甚至有一些相当合理的用例。 使用Prototype框架,它的完成如下。

 new Ajax.Updater('items', '/items.url', { parameters: { evalJS: true} }); 

请参阅Ajax更新程序的文档 。 这些选项位于通用选项集中 。 像往常一样,有一些关于“这个”指向的地方的警告,所以请仔细阅读。

JavaScript代码将在加载时进行评估。 如果内容包含函数myFunc(),那么以后可以真正说myFunc() 。 也许如下。

 if (window["myFunc"]) myFunc() 

这将检查函数是否存在。 也许有人有一个更好的跨浏览器的方式来做这个工作在Internet Explorer 6中。

对于你的代码来说,这似乎是一个相当奇怪的devise – 通常从.js文件直接调用你的函数,然后通过Ajax调用来检索数据通常会更有意义。

不过,我相信它应该通过调用eval()来响应 – 只要它是语法正确的JavaScript代码。

用jQuery,我会用getScript来做

只要记住,如果你通过ajax创build一个函数下面的方式…

 function foo() { console.log('foo'); } 

…通过eval执行它,你可能会遇到上下文问题。 把这个作为你的callback函数:

 function callback(result) { responseDiv = document.getElementById('responseDiv'); responseDiv.innerHTML = result; scripts = responseDiv.getElementsByTagName('script'); eval(scripts[0]); } 

你将在一个函数内部声明一个函数,所以这个新函数只能在该范围内访问。

如果你想在这个场景中创build一个全局函数,你可以这样声明:

 window.foo = function () { console.log('foo'); }; 

但是,我也认为你不应该这样做…

对不起,这里有任何错误…

我想补充一点,在jQuery中有一个eval函数,可以让你在全局范围内评估代码,从而避免任何上下文问题。 该函数被称为globalEval() ,它为我的目的很好。 它的文档可以在这里find。

这是jQuery API文档提供的示例代码:

 function test() { jQuery.globalEval("var newVar = true;") } test(); // newVar === true 

这个函数在加载外部脚本时非常有用,你显然正在试图去做。

一个做这样的事情的清单:

  1. 返回的Ajax响应是eval(ed)。
  2. 函数声明为func_name = function() {...}

更好的是,像Prototype一样使用处理它的框架。 你有Ajax.updater

PHP端代码文件名称class.sendCode.php

 <?php class sendCode{ function __construct($dateini,$datefin) { echo $this->printCode($dateini,$datefin); } function printCode($dateini,$datefin){ $code =" alert ('code Coming from AJAX {$this->dateini} and {$this->datefin}');"; //Insert all the code you want to execute, //only javascript or Jquery code , dont incluce <script> tags return $code ; } } new sendCode($_POST['dateini'],$_POST['datefin']); 

现在从你的Html页面,你必须触发ajax函数来发送数据。

 .... <script src="http://code.jquery.com/jquery-1.9.1.js"></script> .... Date begin: <input type="text" id="startdate"><br> Date end : <input type="text" id="enddate"><br> <input type="button" value="validate'" onclick="triggerAjax()"/> 

现在在我们的本地script.js中,我们将定义ajax

 function triggerAjax() { $.ajax({ type: "POST", url: 'class.sendCode.php', dataType: "HTML", data : { dateini : $('#startdate').val(), datefin : $('#enddate').val()}, success: function(data){ $.globalEval(data); // here is where the magic is made by executing the data that comes from // the php class. That is our javascript code to be executed } }); } 

这听起来不是一个好主意。

您应该从Ajax方法返回的数据中抽取出包含在JavaScript代码的其余部分中的函数。

不过为什么它是值得的(我不明白你为什么要在一个div中插入一个脚本块),甚至可以访问脚本块中写入的内联脚本方法。

我通常的ajax调用函数:

 function xhr_new(targetId, url, busyMsg, finishCB) { var xhr; if(busyMsg !== undefined) document.getElementById(targetId).innerHTML = busyMsg; try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) { try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); } catch(e2) { try { xhr = new XMLHttpRequest(); } catch(e3) { xhr = false; } } } xhr.onreadystatechange = function() { if(xhr.readyState == 4) { if(xhr.status == 200) { var target = document.getElementById(targetId) target.innerHTML = xhr.responseText; var scriptElements = target.getElementsByTagName("script"); var i; for(i = 0; i < scriptElements.length; i++) eval(scriptElements[i].innerHTML); if(finishCB !== undefined) finishCB(); } else document.getElementById(targetId).innerHTML = 'Error code: ' + xhr.status; } }; xhr.open('GET', url, true); xhr.send(null); // return xhr; } 

一些解释:
targetId是ajax调用结果文本所在的(通常是div)元素ID。
url是ajax调用url。
busyMsg将是目标元素中的临时文本。
当ajax事务成功完成时, finishCB将被调用。
正如你在xhr.onreadystatechange = function() {...}看到的,所有的<script>元素都将从ajax响应中收集,并且将被逐个运行。 它似乎对我来说很好。 最后两个参数是可选的。

我已经testing了这个,它的工作原理。 有什么问题? 只需把你的javascript元素中的新function,然后调用它。 它会工作。

我尝试了所有在这里提供的技术,但最后的工作方式是简单地把JavaScript函数放在页面/文件应该发生的地方,然后从Ajax的响应部分简单地调用它作为一个函数:

 ... }, function(data) { afterOrder(); } 

这是第一次尝试,所以我决定分享。

这个代码的工作,而不是eval的HTML我将追加到脚本的头部

 function RunJS(objID) { //alert(http_request.responseText); var c=""; var ob = document.getElementById(objID).getElementsByTagName("script"); for (var i=0; i < ob.length - 1; i++) { if (ob[i + 1].text != null) c+=ob[i + 1].text; } var s = document.createElement("script"); s.type = "text/javascript"; s.text = c; document.getElementsByTagName("head")[0].appendChild(s); } 

我今天解决了这个问题,把我的JavaScript放在响应HTML的底部。

我有一个AJAX请求返回了一堆叠加显示的HTML。 我需要在返回的HTML / overlay响应中附加一个单击事件。 在普通的页面上,我会将我的JavaScript包装在“window.onload”或“$(document).ready”中,以便在新的叠加层的DOM被渲染后,将事件处理程序附加到DOM对象上。因为这是一个AJAX响应,而不是一个新的页面加载,事件从未发生,浏览器从来没有执行我的JavaScript,我的事件处理程序从来没有附加到DOM元素,我的新function不起作用。 再一次,我通过在文档的头部不使用“$(document).ready”来解决“在AJAX响应问题中执行JavaScript”,而是通过将JavaScript放在文档的末尾,并在HTML / DOM已被渲染。

如果您的AJAX脚本运行时间超过几毫秒,则eval()将始终提前运行,并在AJAX使用您要执行的脚本填充它之前评估空响应元素。

而不是与计时和eval(),这是一个非常简单的解决方法,应该在大多数情况下工作,可能是更安全一点。 使用eval()通常是皱眉,因为被评估为代码的字符可以很容易地在客户端操纵。

概念

  1. 在主页面中包含您的JavaScriptfunction。 编写它,以便任何dynamic元素可以被接受为参数。
  2. 在你的AJAX文件中,通过使用正式的DOM事件(onclick,onfocus,onblur,onload等等)来调用函数。根据响应中的其他元素,你可以非常聪明地使它感觉无缝。 传递你的dynamic元素作为参数。
  3. 当你的响应元素被填充并且事件发生时,函数运行。

在这个例子中,我想将一个dynamic的自动完成列表从jquery-ui库附加到一个AJAX元素,在元素添加到页面之后。 很简单,对吧?

start.php

 <!DOCTYPE html> <html> <head> <title>Demo</title> <!-- these libraries are for the autocomplete() function --> <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/ui-lightness/jquery-ui.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <script type="text/javascript"> <!-- // this is the ajax call function editDemoText(ElementID,initialValue) { try { ajaxRequest = new XMLHttpRequest(); } catch (e) { try { ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { return false; }}} ajaxRequest.onreadystatechange = function() { if ( ajaxRequest.readyState == 4 ) { var ajaxDisplay = document.getElementById('responseDiv'); ajaxDisplay.innerHTML = ajaxRequest.responseText; } } var queryString = "?ElementID="+ElementID+"&initialValue="+initialValue; ajaxRequest.open("GET", "ajaxRequest.php"+queryString, true); ajaxRequest.send(null); } // this is the function we wanted to call in AJAX, // but we put it here instead with an argument (ElementID) function AttachAutocomplete(ElementID) { // this list is static, but can easily be pulled in from // a database using PHP. That would look something like this: /* * $list = ""; * $r = mysqli_query($mysqli_link, "SELECT element FROM table"); * while ( $row = mysqli_fetch_array($r) ) { * $list .= "\".str_replace('"','\"',$row['element'])."\","; * } * $list = rtrim($list,","); */ var availableIDs = ["Demo1","Demo2","Demo3","Demo4"]; $("#"+ElementID).autocomplete({ source: availableIDs }); } //--> </script> </head> <body> <!-- this is where the AJAX response sneaks in after DOM is loaded --> <!-- we're using an onclick event to trigger the initial AJAX call --> <div id="responseDiv"><a href="javascript:void(0);" onclick="editDemoText('EditableText','I am editable!');">I am editable!</a></div> </body> </html> 

ajaxRequest.php

 <?php // for this application, onfocus works well because we wouldn't really // need the autocomplete populated until the user begins typing echo "<input type=\"text\" id=\"".$_GET['ElementID']."\" onfocus=\"AttachAutocomplete('".$_GET['ElementID']."');\" value=\"".$_GET['initialValue']."\" />\n"; ?> 

Federico Zancan的回答是正确的,但是您不必为您的脚本提供一个ID并评估所有脚本。 只是评估你的函数名称,它可以被调用。

为了在我们的项目中实现这个function,我们编写了一个代理函数来调用Ajax响应中返回的函数。

 function FunctionProxy(functionName){ var func = eval(functionName); func(); }