我有一个发送Ajax命令的系统,该命令返回一个带有功能的脚本块。在将这些数据正确插入DIV中之后,我希望能够调用此函数来执行所需的操作。
这可能吗?
Answers:
我想以这种形式正确解释您的问题:“好的,我已经用完所有Ajax内容了;我只是想知道从那时起任何时候是否都可以调用插入到DIV中的JavaScript函数。 ,也就是说,我不想在上下文中将其称为“回调返回”。
好的,如果您的意思是这样,那么可以在以下情况下在浏览器中的页面持久性期间的任何时候调用新代码:
1)您的Ajax回调返回的JavaScript代码在语法上必须可以;
2)即使将函数声明插入到<script>
现有<div>
元素中的块中,浏览器也不知道新函数的存在,因为声明代码从未执行过。因此,您必须eval()
由Ajax回调返回的声明代码,以便有效地声明新函数并使它在整个页面生命周期中都可用。
即使很虚构,此代码也可以解释这个想法:
<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,但是概念是相同的(即使我选择的示例确定不是很聪明:-)
一般来说,我不质疑您的解决方案设计,即在单独的.js文件等中对函数进行外部化+泛化是否适当,但请注意,这样的解决方案可能会引起其他问题,尤其是在您的Ajax调用应重复执行,即,如果同一函数的上下文发生更改,或者如果考虑到已声明的函数持久性,那么也许您应该认真考虑将设计更改为该线程中建议的示例之一。
最后,如果我误解了您的问题,并且您谈论的是当您的Ajax回调返回时该函数的上下文调用,那么我的感觉是建议由krosenvold描述的Prototype方法,因为它是跨浏览器,经过测试且功能齐全的,这可以为您提供更好的未来实施路线图。
注意:eval()很容易被滥用,可以说该请求被第三方拦截并向您发送了不可信的代码。然后,使用eval()将运行此不受信任的代码。有关eval()的危险,请参见此处。
在返回的HTML / Ajax / JavaScript文件中,您将具有一个JavaScript标签。给它一个ID,例如runscript。在这些标签中添加ID并不常见,但是需要专门引用它。
<script type="text/javascript" id="runscript">
alert("running from main");
</script>
在主窗口中,然后通过仅评估该JavaScript代码的NEW块(在本例中为runscript)来调用eval函数:
eval(document.getElementById("runscript").innerHTML);
它至少在Internet Explorer 9和Google Chrome中有效。
<script id="my-secure-id">
标签中。通过使用此解决方案,看不到任何增加的安全性。实际上,它只会给您带来错误的安全感,这更加危险。但是大约6年后,HTTPS现在变得非常普遍。我相信通过安全的HTTPS不可能对eval()进行攻击。我认为那是错误的吗?
这是完全可能的,甚至有一些相当合法的用例。使用原型框架,其操作如下。
new Ajax.Updater('items', '/items.url', {
parameters: { evalJS: true}
});
请参阅Ajax更新程序的文档。这些选项在通用选项集中。像往常一样,关于“此”指向何处有一些警告,因此请阅读精美的印刷品。
JavaScript代码将在加载时进行评估。如果内容包含功能,myFunc(),
您实际上可以myFunc()
稍后再说。可能如下。
if (window["myFunc"])
myFunc()
这将检查该功能是否存在。也许有人有更好的跨浏览器方式可以在Internet Explorer 6中运行。
请记住,如果您通过以下方式通过ajax创建函数...
function foo()
{
console.log('foo');
}
...并通过eval执行它,您可能会遇到上下文问题。将此作为您的回调函数:
function callback(result)
{
responseDiv = document.getElementById('responseDiv');
responseDiv.innerHTML = result;
scripts = responseDiv.getElementsByTagName('script');
eval(scripts[0]);
}
您将在函数内部声明一个函数,因此只能在该作用域上访问此新函数。
如果要在这种情况下创建全局函数,可以这样声明:
window.foo = function ()
{
console.log('foo');
};
但是,我也认为您不应该这样做...
抱歉在这里有任何错误...
我想补充一点,jQuery中有一个eval函数,允许您全局评估代码,这将使您摆脱任何上下文问题。该函数称为globalEval(),它对我来说非常有用。它的文档可以在这里找到。
这是jQuery API文档提供的示例代码:
function test()
{
jQuery.globalEval("var newVar = true;")
}
test();
// newVar === true
当动态加载您显然试图执行的外部脚本时,此功能非常有用。
PHP辅助代码文件类的名称.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
}
});
}
此代码也可以正常工作,而不是评估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);
}
我通常的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
是一个(通常是div)元素ID,ajax调用结果文本将在该元素ID中使用。
url
是ajax调用网址。
busyMsg
将是目标元素中的临时文本。
finishCB
ajax事务成功完成时将调用。
如您所见,xhr.onreadystatechange = function() {...}
所有<script>
元素都将从ajax响应中收集并逐一运行。它对我来说似乎很好用。最后两个参数是可选的。
我已经对此进行了测试,并且可以正常工作。有什么问题?只需将新函数放入您的javascript元素中,然后调用它即可。它将起作用。
我今天通过将我的JavaScript放在响应HTML的底部解决了这个问题。
我有一个AJAX请求,该请求返回了一堆显示在叠加层中的HTML。我需要将click事件附加到返回的响应HTML /叠加层中的按钮上。在普通页面上,我将JavaScript封装在“ window.onload”或“ $(document).ready”中,以便在呈现新叠加层的DOM之后将事件处理程序附加到DOM对象,但是因为这是AJAX响应而不是新的页面加载,所以该事件从未发生,浏览器从未执行过我的JavaScript,事件处理程序也从未附加到DOM元素上,而我的新功能却无法正常工作。再次,通过不使用文档开头的“ $(document).ready”,解决了“在AJAX响应问题中执行JavaScript”的问题,
如果您的AJAX脚本要花费几毫秒的时间才能运行,则eval()将始终运行并评估空响应元素,然后AJAX会使用您要执行的脚本填充该响应元素。
这不是一个浪费时间和eval()的方法,而是一种非常简单的解决方法,该方法应可在大多数情况下使用,并且可能更安全。通常不赞成使用eval(),因为被评估为代码的字符可以很容易地在客户端进行操作。
在此示例中,我想在将元素添加到页面后,将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并评估所有脚本。只需评估您的函数名称,就可以调用它。
为了在我们的项目中实现这一目标,我们编写了一个代理函数来调用Ajax响应内部返回的函数。
function FunctionProxy(functionName){
var func = eval(functionName);
func();
}