繁体   English   中英

通过动态插入的DOM元素进行AJAX调用,是否需要使用Mutation Observer?

[英]Make AJAX call via dynamically inserted DOM element, do I have to use a Mutation Observer?

在当前应用程序中,页面上有一些元素以“空”开始,并通过AJAX调用加载其显示数据。

一种简单的实现方法是使用一个类(例如.ajax-loader )并遍历每个类,然后从元素本身的data- attribute中加载AJAX数据。

所以像这样( jsfiddle ):

<div class="ajax-loader" data-url="/echo/html/" data-html="<p>hello world</p>" data-delay="1">Loading...</div>

<script>
  $('.ajax-loader').each(function() {
    var ele = $(this);
    var url = ele.data('url');
    var html = ele.data('html');
    var delay = ele.data('delay');

    return $.post({
      url: url,
      data: {
        html: html,
        delay: delay
      }
    }).done(function(d) {
      ele.html(d);
    });
  });
</script>

现在,这可以正常工作,但是,当我需要将这些.ajax-loader元素动态插入页面时,就会出现问题。 我的.each()函数仅运行一次,因此如果在页面中插入了新的.ajax-loader元素,则不会再次运行(您可以通过单击按钮在上一个jsfiddle中看到它)。

因此,我放入了一个突变观察器来检测DOM的变化。 现在我的代码如下所示( jsfiddle ):

<button class="insert-ele">Click to insert new AJAX object</button>
<div id="container">
  <div class="ajax-loader" data-url="/echo/html/" data-html="<p>Hello World!</p>" data-delay="1">Loading...</div>
</div>

<script>
$(document).ready(function() {
  // Insert new ".ajax-loader" objects on button click
  $('.insert-ele').on('click', function(e) {
    $('#container').append('<div class="ajax-loader" data-url="/echo/html/" data-html="<p>I was inserted via JS.</p>" data-delay="1">Loading...</div>');
    e.preventDefault();
  });

  // Define our ajaxLoader function
  var ajaxLoader = function() {
    var ele = $(this);
    ele.addClass('ajax-load-started');

    var url = ele.data('url');
    var html = ele.data('html');
    var delay = ele.data('delay');

    return $.post({
        url: url,
      data: {
        html: html,
        delay: delay
      }
    }).done(function(d) {
        ele.html(d);
      ele.addClass('ajax-load-completed');
      ele.removeClass('ajax-load-started');
    });
  };

  // Loop through each .ajax-loader, and load their AJAX request.
  $('.ajax-loader:not(.ajax-load-completed):not(.ajax-load-started)').each(ajaxLoader);

  // Observe DOM changes, and load AJAX data when it does change
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  var observer = new MutationObserver(function(mutations) {
    $('.ajax-loader:not(.ajax-load-completed):not(.ajax-load-started)').each(ajaxLoader);
  });

  // Activate the observer
  var container = document.getElementById('container');
  observer.observe(container, {
    attributes: true, 
    childList: true, 
    subtree: true
  });
});
</script>

但是,查看突变观察者浏览器兼容性 ,我发现它仅在IE 11中受支持。我需要支持IE 9,可能还需要IE 8,尽管那并不那么重要。

有没有更好的方法可以做到这一点? 或者只是另一种方式可以使我更好地与浏览器兼容?

我也意识到我可以在$('.insert-ele').on('click')处理程序中运行$('.ajax-loader').each()函数,但是我想避免这种情况解决方案,如果可能的话。

突变观察在这里并不适合(无论您如何实现):检查DOM(或任何对象)的更改是很昂贵的,因为它需要保留对象的副本并遍历整个对象事物,递归到对象的属性以检查差异。 就您而言,您无需知道任何更改,而是想知道何时发生了特定事件(将dom元素添加到页面中)。

您想要一个“一刀切”的解决方案是正确的,并且实施起来应该不会太困难。 在某个地方,您有一个AJAX回调负责将这些元素添加到页面中。 (如果对此负责的功能不止一个,那么现在是将它们整合为一个功能的时候了。)当此AJAX回调函数插入DOM元素时,让它a)触发您定义的回调,或b)触发您的其他代码可以监听的自定义事件 (可能通过jQuery,但Backbone和其他库也具有自定义事件实用程序)。 无论您采用哪种方法,都希望插入DOM元素的函数执行允许其他代码响应该操作的操作。

如果负责将DOM元素插入页面的代码是第三方的,这可能会比较棘手。 (这是考虑是否最好编写自己的实现的好时机。)查看该代码的源代码,并仔细检查其是否不支持回调或事件或允许您与其集成的内容。 如果没有,您仍然应该能够通过侦听load事件来响应DOM插入。

每个DOM元素加载到DOM中时都会触发一个load事件。 您不能将事件侦听器附加到正在插入的元素上,因为它们尚不存在,但是您可以使用事件委托 :在load事件的父元素上附加事件侦听器,当元素具有已插入(因为事件从插入的元素到其父元素冒泡了)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM