.append 之后的 jQuery 函数
Posted
技术标签:
【中文标题】.append 之后的 jQuery 函数【英文标题】:jQuery function after .append 【发布时间】:2011-08-29 11:07:58 【问题描述】:jQuery.append
完成后如何调用函数?
这是一个例子:
$("#root").append(child, function()
// Action after append is completly done
);
问题:追加复杂的DOM结构时,在追加函数回调中计算根元素的新大小是错误的。假设 DOM 还没有完全加载,只有添加的复杂 DOM 的第一个子节点。
【问题讨论】:
你应该很好地链接事件;append()
只需要很少的时间。
参见***.com/q/8840580/176140(webkit 浏览器上的 dom 'reflow')
这可能会有所帮助:***.com/a/1489987/1375015
【参考方案1】:
Jquery append 函数返回一个 jQuery 对象,因此您可以在末尾标记一个方法
$("#root").append(child).anotherJqueryMethod();
【讨论】:
我需要在 .append 之后调用我自定义的 javascript 函数,我需要重新计算 root 的大小 你可以使用 jQuery each 方法,但是 append 是一个同步方法,所以你应该可以在下一行做任何你需要做的事情。 @JinDave,你到底需要重新计算什么?孩子的数量,父母的身高,或者 size 是什么意思?【参考方案2】:$('#root').append(child);
// do your work here
Append 没有回调,这是同步执行的代码 - 没有不完成的风险
【讨论】:
我看到太多这样的cmets,而且他们没有帮助。 @david falls,是的,JS 是同步的,但是 DOM 需要时间来更新。如果您需要操作 DOM 附加元素,但元素尚未渲染到 DOM 中,即使附加完成,您的新操作也将不起作用。 (例如:$('#element').on()。【参考方案3】:$('#root').append(child).anotherMethod();
【讨论】:
我需要叫我 javascript 函数,而不是 jQuery 函数【参考方案4】:这里有很多有效的答案,但没有一个能真正告诉你为什么它会这样工作。
在 JavaScript 中,命令一次执行一个,按照它们出现的顺序同步执行,除非您通过使用超时或间隔明确告诉它们是异步的。
这意味着您的 .append
方法将被执行,并且在该方法完成其工作之前不会执行任何其他操作(忽略任何可能存在的超时或间隔)。
总而言之,不需要回调,因为.append
将同步运行。
【讨论】:
这都是真的,但这是我的问题:我追加了复杂的 DOM,并且在追加之后,我计算了根元素的新大小,但是我得到了错误的数字。并认为,问题是这样的: DOM 仍未完全加载,只有第一个孩子 (.append("")) @JinDave,你指的这个 size 是什么?是孩子的数量,父母的身高还是你需要计算的? @marcus-ekwall jsfiddle.net/brszE/3 这只是写法,不是工作代码, @DavidHorák 那么为什么这是公认的答案?确实,即使发生更改,代码也不会阻塞,直到完全回流非常惊讶这有 32 票赞成!(或者我什至不会导致回流)类似于[这里](***.com/questions/8840580/…)的答案可能是矿石相关。 我同意 Andreas,这个答案是不正确的。问题是即使 append 已经返回,该元素在 DOM 中仍然可能不可用(取决于浏览器,在某些浏览器中工作,在其他浏览器中中断)。使用超时仍然不能保证元素会在 DOM 中。【参考方案5】:我认为这很好回答,但这对于处理“subChild_with_SIZE”更具体一些(如果它来自父级,但你可以从它可能的位置调整它)
$("#root").append(
$('<div />',
'id': 'child'
)
)
.children()
.last()
.each(function()
$(this).append(
$('<div />',
'id': $(this).parent().width()
)
);
);
【讨论】:
【参考方案6】:$.when($('#root').append(child)).then(anotherMethod());
【讨论】:
$.when
仅适用于那些返回承诺对象的对象
它正在工作,但在控制台上出现错误..“然后不是函数”
这仅在您立即调用anotherMethod()
时才有效。它没有作为回调传递。
这毫无意义。【参考方案7】:
好吧,我在重新计算大小时遇到了完全相同的问题,经过数小时的头痛后,我不得不不同意 .append()
的行为严格同步。至少在谷歌浏览器中。请参阅以下代码。
var input = $( '<input />' );
input.append( arbitraryElement );
input.css( 'padding-left' );
在 Firefox 中可以正确检索 padding-left 属性,但在 Chrome 中它是空的。就像我想的所有其他 CSS 属性一样。经过一些实验后,我不得不以 10 毫秒的延迟将 CSS 'getter' 包装到 setTimeout()
中,我知道这很糟糕,但只有一个在 Chrome 中工作。
如果你们中有人知道如何更好地解决这个问题,我将不胜感激。
【讨论】:
这对我帮助很大:***.com/q/8840580/176140 - 意思是 append() 是同步的,但 DOM 更新不是 在这种情况下,setTimeout 并不难看(只有 10ms)。每次您请求“dom”操作时,chrome 都会等待您的代码结束后再执行。因此,如果您调用 item.hide 后跟 item.show,它将什么也不做。当您的执行功能结束时,它会将您的更改应用到 DOM。如果您需要在继续之前等待“dom”更新,只需执行 CSS/DOM 操作,然后调用 settimeout(function()what to do next);。 settimeout 就像 vb6 中一个很好的旧“doevents”!它告诉浏览器执行它的等待任务(更新 DOM),然后返回到您的代码。 查看使用.ready()
更好、更优雅的解决方案的答案。【参考方案8】:
我有另一个可能对某人有用的变体:
$('<img src="http://example.com/someresource.jpg">').load(function()
$('#login').submit();
).appendTo("body");
【讨论】:
对于那些认为它已被弃用和删除的人来说,这是正确的,但您仍然可以像...on('load', function() ...
一样使用它,请参见此处:***.com/a/37751413/2008111【参考方案9】:
我知道这不是最佳解决方案,而是最佳实践:
$("#root").append(child);
setTimeout(function()
// Action after append
,100);
【讨论】:
我认为这不是一个好习惯。 100 是一个任意数字,一个事件可能需要更长的时间。 走错路了。它可能并不总是需要 100 毫秒 在此处查看我的答案,了解为什么会这样(数字可能/应该是 0,而不是 100):***.com/questions/6068955/… 这至少比使用 .ready 的答案更好。【参考方案10】:我在为移动设备编写 html5 代码时遇到了这个问题。某些浏览器/设备组合会导致错误,因为 .append() 方法没有立即反映 DOM 中的更改(导致 JS 失败)。
针对这种情况的快速解决方案是:
var appint = setInterval(function()
if ( $('#foobar').length > 0 )
//now you can be sure append is ready
//$('#foobar').remove(); if elem is just for checking
//clearInterval(appint)
, 100);
$(body).append('<div>...</div><div id="foobar"></div>');
【讨论】:
间隔不应该用于等待代码构造函数完成。这是完全不可靠的。【参考方案11】:是的,您可以向任何 DOM 插入添加 回调 函数:$myDiv.append( function(index_myDiv, HTML_myDiv)
//....
return child
)
查看 JQuery 文档:http://api.jquery.com/append/
这是一个实用的类似示例:
http://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_html_prepend_func
【讨论】:
摆弄 w3schools 示例,您可以检查第二个参数,将.prepend()
方法替换为: $("p").prepend(function(n, pHTML) return "This p 元素 (\""+pHTML+"\") 有索引 " + n + ". ";
您显然不了解该示例的目的..它不是说内容已附加的回调,而是返回 what 的回调函数被追加。
@vsync:确实如此。你显然没有看懂我的回答。 "child" 是 what 已被附加,而 not 是在附加时。【参考方案12】:
我最近遇到了类似的问题。我的解决方案是重新创建集合。让我尝试演示一下:
var $element = $(selector);
$element.append(content);
// This Doesn't work, because $element still contains old structure:
$element.fooBar();
// This should work: the collection is re-created with the new content:
$(selector).fooBar();
希望这会有所帮助!
【讨论】:
这对我没有帮助。 :(【参考方案13】:对于图像和其他来源,您可以使用:
$(el).one('load', function()
// completed
).each(function()
if (this.complete)
$(this).load();
);
【讨论】:
【参考方案14】:我遇到了同样的问题,并找到了一个简单的解决方案。 调用 append 函数后添加一个准备好的文档。
$("#root").append(child);
$(document).ready(function ()
// Action after append is completly done
);
【讨论】:
不错。这对我有用(我使用 Handlebars 和 JSON 附加 HTML,当然还有一个常规的 document.ready 发生得太早了)。 @KatharineOsborne 这与“常规 document.ready”没有什么不同。 document.ready 仅在一种特定情况下被调用,不同地使用它并不会使其工作方式不同。 好吧,我离开评论已经一年多了,但是 IIRC,你称之为的上下文很重要(即在函数中)。此后代码已传递给客户端,因此我无法再访问它以重新挖掘。【参考方案15】:使用MutationObserver
可以作为jQuery append
方法的回调:
我已经在another question解释过了,这次我只举现代浏览器的例子:
// Somewhere in your app:
var observeDOM = (() =>
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function(obj, callback)
if( MutationObserver )
// define a new observer
var obs = new MutationObserver(function(mutations, observer)
if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
callback(mutations);
);
// have the observer observe foo for changes in children
obs.observe( obj, childList:true, subtree:true );
return obs;
)();
//////////////////
// Your code:
// setup the DOM observer (on the appended content's parent) before appending anything
observeDOM( document.body, ()=>
// something was added/removed
).disconnect(); // don't listen to any more changes
// append something
$('body').append('<p>foo</p>');
【讨论】:
+1。在所有答案中,你最适合。但是,在我的情况下它不起作用,将各种行添加到表中,因为它进入了无限循环。对表格进行排序的插件将更改 DOM,因此它将无限次调用观察者。 @Azevedo - 为什么它会是无限的?我确定它是有限的。无论如何,您可以通过一点创意将 sort 功能与添加的行“事件”分开。有办法的。 当排序插件对表进行排序时,它会触发观察者(dom改变),这将再次触发排序。现在我在想......我可以计算表格的行数并让观察者只有在行计数器发生变化时才调用排序器。 我得到的只是......未捕获的类型错误:无法在“MutationObserver”上执行“观察”:参数 1 不是“节点”类型。 @Scott - 你可能写了你的脚本在DOM准备好了.....加载你的脚本仅在<script>
标记之后或放置在底部,</body>
之前【参考方案16】:
尽管 Marcus Ekwall 关于追加的同步性是绝对正确的,但我也发现在奇怪的情况下,有时当下一行代码运行时浏览器并未完全呈现 DOM。
在这种情况下,shadowdiver 解决方案是正确的 - 使用 .ready - 但是将调用链接到原始附加会更整洁。
$('#root')
.append(html)
.ready(function ()
// enter code here
);
【讨论】:
这在任何情况下都是绝对错误和无用的。 api.jquery.com/ready 嗨,凯文,以什么方式? 当且仅当文档尚未准备好时,使用 .ready 等待附加元素“渲染”绝对没有任何好处,而不是简单地使用 settimeout .如果文档准备就绪,则代码将同步运行,因此有用的影响为零。 我认为 ready 不会等待附加文档加载,而是等待整个 DOM 加载。我写这个答案已经过去了大约 3 年,但我想我更多地评论了上面的影子潜水员,但当时没有能力发表评论。 实际上,这比预期的要好。比这里的任何其他答案都好。【参考方案17】:我对这里的所有答案感到惊讶......
试试这个:
window.setTimeout(function() /* your stuff */ , 0);
注意 0 超时。这不是一个任意数字......据我所知(尽管我的理解可能有点不稳定),有两个 javascript 事件队列 - 一个用于宏事件,一个用于微事件。 “更大”范围的队列包含更新 UI(和 DOM)的任务,而微队列执行快速任务类型的操作。
还要意识到设置超时并不能保证代码完全按照指定的值执行。这实际上是将函数放入更高的队列(处理 UI/DOM 的队列),并且在指定时间之前不运行它。
这意味着将超时设置为 0 会将其放入 javascript 事件队列的 UI/DOM 部分,以便在下一个可能的机会运行。
这意味着 DOM 将使用所有先前的队列项进行更新(例如通过 $.append(...);
插入,并且当您的代码运行时,DOM 完全可用。
(p.s. - 我从 JavaScript Ninja 的秘密中学到了这一点 - 一本很棒的书:https://www.manning.com/books/secrets-of-the-javascript-ninja)
【讨论】:
多年来我一直在添加setTimeout()
,但不知道为什么。谢谢你的解释!【参考方案18】:
最干净的方法是一步一步地做。使用 each 函数遍历每个元素。追加该元素后,将其传递给后续函数以处理该元素。
function processAppended(el)
//process appended element
var remove = '<a href="#">remove</a>' ;
$('li').each(function()
$(this).append(remove);
processAppended(this);
);
【讨论】:
以上是关于.append 之后的 jQuery 函数的主要内容,如果未能解决你的问题,请参考以下文章
jquery after append appendTo三个函数的区别
jQuery中append(),prepend()与after(),before()的区别