[英]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.