【问题标题】:Javascript not executing when loaded via XMLHttpRequest but does when loaded with jQuery.loadJavascript 在通过 XMLHttpRequest 加载时不执行,但在通过 jQuery.load 加载时执行
【发布时间】:2016-12-12 22:00:28
【问题描述】:

在将脚本转换为不需要 jQuery 时,我发现如果我通过 XMLHttpRequest 加载我的内容(带有 html 和 javascript 的部分 html 页面),则部分页面中的 javascript 不起作用。但是如果我使用 jQuery.load 加载部分,它确实有效。

我尝试深入研究 jQuery 的加载函数,看看它是否在做任何特别的事情,但我没有发现任何问题。几天来,我一直在用头撞墙并寻找答案,但无济于事。

我做错了什么/如何让它像使用 jQuery.load 加载时一样工作?

编辑

通过从片段中的 html 中分离出我的 javascript 并使用此处建议的技术加载 javascript,我得到了 XMLHttpRequest 方法:https://stackoverflow.com/a/11695198/362958。但是,这仍然没有解释为什么 jQuery.load 有效。 jQuery 是否完美地解析 HTML 并对它在加载的内容中找到的任何脚本执行相同的操作?

我已经使用以下代码设置了一个 plunker (https://plnkr.co/edit/wE9RuULx251C5ARnUbCh) 来演示该问题。注意:一旦您使用 jQuery 加载片段,它将继续工作,您必须重新启动 plunk 才能使 XMLHttpRequest 方法再次失败。

index.html:

<!DOCTYPE html>
<html>

  <head>
    <script data-require="jquery@*" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>

  <h3>Buttons</h3>  
    <div>
      <input type="button" value="Load with XMLHttpRequest" onclick="loadXMLDoc('ajaxContentDiv', 'fragmentToLoad.html');">  (Links do not work if loaded this way... Script from fragmentToLoad.html not loaded in DOM?) <br/><br/>
      <input type="button" value="Load with JQuery" onclick="jQuery('#ajaxContentDiv').load('fragmentToLoad.html');">  (Links will work if loaded this way)
    </div>
<br/>
<br/>
<br/>
<div id="ajaxContentDiv">Content will load here...</div>

  </body>

</html>

script.js:

function loadXMLDoc(targetDivName, url) {

  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open("GET", url, true);
  xmlhttp.onreadystatechange = function () {
      if (xmlhttp.readyState == XMLHttpRequest.DONE) {
          if (xmlhttp.status == 200) {
              document.getElementById(targetDivName).innerHTML = xmlhttp.responseText;
          }
      }
  };
  xmlhttp.send();
}

fragmentToLoad.html:

<div id="divToBeUpdated">
  <span id="stringBox">String here</span>
</div>
<br/>
<h3>Links</h3>
<div>
  <a href="#" onclick="updateDiv('Hello World 1');">Link 1</a><br>
  <a href="#" onclick="updateDiv('Hello World 2');">Link 2</a><br>
  <a href="#" onclick="updateDiv('Hello World 3');">Link 3</a><br>
</div>

<script>
  function updateDiv(string){
    var stringBox = document.getElementById('stringBox');
    stringBox.innerHTML = string;
  }
</script>

【问题讨论】:

  • updateDiv 函数在document 加载时的全局属性事件中未定义在html
  • @Barmar OP 的问题比链接的问题和答案稍微复杂一些。也就是说,将fragmentToLoad.html 中不是&lt;script&gt;html 元素与fragmentToLoad.html 中的&lt;script&gt; 元素分开;此外,OP 需要将 click 事件侦听器附加到每个 a 元素,链接的问题没有解决。从这里的角度来看,链接的问题不是“完全重复”。
  • jQuery 解析 HTML 并搜索 &lt;script&gt; 标签,并自行模拟它们,因为分配给 .innerHTML 不会执行脚本。
  • OP 正在尝试使用 jQuery。链接问题地址如何将click 事件附加到附加到document 的动态&lt;a&gt; 元素?
  • .load() 函数中没有任何东西跳出来的原因是它是在 .html() 函数中完成的。 .load() 只是一个快捷方式,它执行 AJAX 调用,然后在结果上使用 .html()。找到执行&lt;script&gt; 模拟的实际代码可能很困难,因为它被埋在了深处。

标签: javascript jquery html ajax xmlhttprequest


【解决方案1】:

您可以使用单个 .html 文件,并且通过拆分 html 内容,您在正确的轨道上 - 尽管您也可以拆分单个文件的 html 内容,而不是请求两个文件。 @Barmar 在 comment 上解释了 jQuery 的 .load() 方法的功能。

script.js

function loadXMLDoc(targetDivName, url) {

  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open("GET", url, true);
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == XMLHttpRequest.DONE) {
      if (xmlhttp.status == 200) {
        // create a `div` elemenent, append response to `div` element
        // get specific elements by `id`, append `script` element to `document.body`
        var content = document.createElement("div");
        content.innerHTML = xmlhttp.responseText
        var div = content.querySelector("#htmlContent");
        var contentScript = content.querySelector("#contentScript");
        var script = document.createElement("script");
        script.textContent = contentScript.textContent;
        document.getElementById(targetDivName).innerHTML = div.innerHTML;
        document.body.appendChild(script);
      }
    }
  };
  xmlhttp.send();
}

fragmentToLoad.html

<div id="htmlContent">
  <div id="divToBeUpdated">
    <span id="stringBox">String here</span>
  </div>
  <br/>
  <h3>Links</h3>
  <div class="links">
    <a href="#">Link 1</a>
    <br>
    <a href="#">Link 2</a>
    <br>
    <a href="#">Link 3</a>
    <br>
  </div>
</div>
<script type="text/javascript" id="contentScript">
  function updateDiv(string) {
    var stringBox = document.getElementById('stringBox');
    stringBox.innerHTML = string;
  }
  // attach `click` event to `.link a` elements here
  var links = document.querySelectorAll(".links a");
  for (var i = 0; i < links.length; i++) {
    (function(link, i) {
      console.log(i)
      link.addEventListener("click", function(e) {
        e.preventDefault();
        updateDiv("Hello World " + i)
      })
    })(links[i], i)
  }
</script>

plnkrhttps://plnkr.co/edit/7fLtGRSV7WlH2enLbwSW?p=preview

【讨论】:

  • 感谢您的示例并指出通过使用选择器,内容仍然可以存在于单个文档中。在我的最终代码中,我仍然能够使用 onclick="updateDiv(.... 而不是附加到链接的事件处理程序。
  • @John 不愿深入研究“好的做法”、“坏做法”的估计;首先,请参阅stackoverflow.com/questions/36388227/…。当前的问题解决了吗?
  • 好点。 HTML/Javascript 不是我的故乡,所以这些天我已经失去了一些最佳实践。我对您提出的方法的唯一问题是我的实际代码将在音频标签上设置一个 src 元素并显示要在 div 中播放的音频的标题。您将如何转换这些:播放播放
  • @John 您可以将值存储在数组var arr = [['/AudioFile321.mp3','Audio File 321'], ['/HelloWorld123.mp3','Hello World 123']] 中,将i 处的数组元素传递给for 循环内立即调用的函数表达式,然后在调用@ 时使用Function.prototype.apply() 987654334@ 在事件处理程序 (function(link, array) {link.addEventListener("click", function(e) {e.preventDefault();updateDiv.apply(null, array)})})(links[i], arr[i]) 内。
猜你喜欢
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多