【问题标题】:Event to determine when innerHTML has loaded确定何时加载 innerHTML 的事件
【发布时间】:2023-04-05 23:41:01
【问题描述】:

是否可以确定设置innerHTML 何时已加载? 我不确定它是否是同步操作。我假设“构建 DOM”是同步的,但加载标签、内容等不是。

简而言之 - 有没有办法在 innerHTML 完成加载时获取事件?

谢谢!

【问题讨论】:

  • innerHTML 是什么?身体,一个元素……
  • 任何元素的innerHTML。想象一下,我有一大块 HTML 想要转储到 divsinnerHTML
  • 这个问题太模糊了。 “完成加载”是什么意思?我想答案会根据您注入的内容类型而有很大不同。图片、脚本、样式表、Flash、小程序、iframe、视频、音频?

标签: javascript


【解决方案1】:

您需要使用DOM Mutation Observers,目前仅适用于Chrome and Firefox。 它们取代了破坏性能的 DOM 突变事件。

示例代码,来自 HTML5Rocks:

var insertedNodes = [];
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations) {
 mutations.forEach(function(mutation) {
   for (var i = 0; i < mutation.addedNodes.length; i++)
     insertedNodes.push(mutation.addedNodes[i]);
 })
});

observer.observe(document, { childList: true });
console.log(insertedNodes);

这里是 DOM4 spec。 请不要使用setTimeout() 黑客。 :)

【讨论】:

    【解决方案2】:

    由于通过innerHTML 添加的img 元素确实触发了它们的onload 事件,您可以在插入innerHTML 的原始代码的末尾添加一个小图像,并且在它们的onload 事件中您可以调用一个函数。也可以删除里面的图片。

    <img src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' onload='hasLoadedFunc();this.parentNode.removeChild(this);'>
    

    JSFiddle sample

    src='data:image' 代码在这里很有用,因为不需要特定的图像。

    我在另一个答案中找到了这个解决方案,只是找不到。找到参考后,我将编辑此解决方案。

    【讨论】:

    • 工作就像一个魅力!
    【解决方案3】:

    如果您替换整个文档 HTML,@zahanm 答案似乎不起作用,这正是我所需要的。所以我不得不退回到setInterval。基于@shawndumas 的回答,我使用Promise 创建了一种更现代的方法:

    function waitUntilSelectorExist(selector, interval = 100, timeout = 20000) {
        let intervalId;
        let elapsed = 0;
    
        let promise = new Promise(function(resolve, reject) {
            intervalId = setInterval(() => {
                let element = document.querySelector(selector);
                if (element !== null) {
                    clearInterval(intervalId);
                    resolve(element);
                }
                elapsed += interval;
                if (elapsed > timeout) {
                    clearInterval(intervalId);
                    reject(`The selector ${selector} did not enter within the ${timeout}ms frame!`);
                }
            }, interval);
        });
    
        return promise;
    }
    

    我也改用querySelector,所以你可以搜索你喜欢的任何选择器,.class#id等。

    如果函数在文档中找到 querySelectorPromise 将解析,因此您可以将其与新的 await 关键字一起使用。

    (async() => {
        try {
            await waitUntilSelectorExist("#test");
            console.log("Do stuff!");
        } catch (error) {
            console.warn(error); // timeout!
        }
    })();
    

    当然,如果您真的只是更改文档中的某些元素,您也可以将 MutationObserver 包裹在 Promise 中:

    function waitUntilSelectorExist(selector) {
        let MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    
        let promise = new Promise(function(resolve) {
            let observer;
            observer = new MutationObserver(function(mutations) {
                let element = document.querySelector(selector);
                if (element !== null) {
                    observer.disconnect();
                    resolve();
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
        });
        
        return promise;
    }
    

    【讨论】:

      【解决方案4】:
       var waitUntil = function (fn, condition, interval) {
          interval = interval || 100;
      
          var shell = function () {
                  var timer = setInterval(
                      function () {
                          var check;
      
                          try { check = !!(condition()); } catch (e) { check = false; }
      
                          if (check) {
                              clearInterval(timer);
                              delete timer;
                              fn();
                          }
                      },
                      interval
                  );
              };
      
          return shell;
      };
      

      像这样使用它:

      waitUntil(
        function () {
          // the code you want to run here...
        },
        function() {
          // the code that tests here... (return true if test passes; false otherwise)
          return !!(document.getElementById('<id of the div you want to update>').innerHTML !== '');
        },
        50 // amout to wait between checks
      )();
      

      【讨论】:

      • 谢谢.. 解释一下这是基于什么前提?你的例子有点难以理解。谢谢!
      • 在示例中,我将两个匿名函数和一个整数发送到 waitUtil 函数。第一个函数只有在第二个返回真结果时才会运行。该整数用于设置第二个函数再次运行之前的时间(返回false之后)。
      • 哈哈,我理解那部分,但实际上我从根本上得到的是为什么,如果返回 !!(document.getElementById('')) ;返回 true,表示它已加载? (你如何关联加载时的真实回报)
      • getElementById 的结果将为 null 或 dom 对象。前者是假的,后者是真的。这 !!在 js 中进行布尔强制,因此 falsey 值变为 false,truthy 值为 true。如果 getElementById 返回 dom 对象,您就可以开始了。 (但如果你想学究气,你可以做 document.getElementById('theId').innerHTML)
      • 抱歉,我仍然不清楚 - 在示例中,您引用的 div 是我插入数据的父潜水吗? (例如 thisDiv.innerHTML)。还是您指的是包含在 innerHTML 内容中的 Div?如果是前者,那我不明白你说的为什么是真的。如果是后者,那么问题是我可能不知道任何 Id :(
      【解决方案5】:

      是的,你可以这样做:

      window.document.getElementById("Testing").innerHTML = 
      "<img src='test.jpg' width='200' height='400'>";
      alert('test');
      

      javascript 将按顺序执行,因此一旦您的 innerHTML 被加载,警报就会消失。

      另外,看看Javascript Execution Model

      【讨论】:

      • 谢谢。但是上述 a) 是否保证图像已完全加载?至少我确定它保证图像元素在 DOM 中?
      【解决方案6】:

      如何创建一个容器 div 并为其添加一个 onload 事件处理程序。

      var container = document.createElement('div');
      container.addEventListener('load', function() {
          // Do something here
      }, false);
      container.innerHTML = '<h1>Here comes my HTML</h1>';
      document.getElementById('someId').appendChild(container);
      

      【讨论】:

      • “怎么样”是指“似乎是个好主意”还是“我已经尝试过并且知道它有效”?
      • 它适用于图像,但不适用于一般 HTML。一种可能的解决方案是为 HTML jsfiddle.net/b2wsc/3 中的所有图像添加处理程序
      【解决方案7】:

      您是否尝试过使用window.onload 事件?此事件在整个页面完全加载时触发,包括其所有内容,如图像、脚本、内框等。

      附:如果您使用 JQuery 库,那么您可以使用他们的 $(window).load 事件包装器。

      【讨论】:

        猜你喜欢
        • 2023-03-30
        • 2013-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-17
        • 1970-01-01
        相关资源
        最近更新 更多