简体   繁体   中英

jQuery: Using .after() or .before() adds element to last item in selection only

I've been using jQuery for a while but this is a new one. A simplified example:

HTML

<div class='custom'></div>
<div class='custom'></div>
<div class='custom'></div>

jQuery:

var $customElems = $('.custom'),
    $spanOuter   = $('<span class="outer"/>'),
    $spanInner   = $('<span class="inner"/>');

$customElems.each( function() {
    $(this).wrap($spanOuter).after($spanInner);
});

JSFiddle: http://jsfiddle.net/a3ZK8/

I would have expected the 'inner' span to be added to all three elements in the selection but it gets always inserted into the last one only (no matter how many). I tried it with .before(), with and without the chaining, same result. What am I missing??

The problem is you are using a reference to a jQuery object.

Hence you keep moving the object reference around within each iteration.

If you have no events attached or no need for the span to be a jQuery object then just pass the parameter as a HTML string literal instead of an object reference

Cloning a jQuery object that doesn't need to be a jQuery object in the first place is just redundant processing and unnecessary overhead.

Change your jQuery object to a string similar to this:

spanInnerString  = '<span class="inner"/>';

and your method like this:

$(this).wrap($spanOuter).after(spanInner);

The result is:

<span class="outer"><div class="custom"></div><span class="inner"></span></span>
<span class="outer"><div class="custom"></div><span class="inner"></span></span>
<span class="outer"><div class="custom"></div><span class="inner"></span></span>

DEMO - Passing parameter as HTML string


Off course, the same goes for the outer span. Don't create jQuery objects unless you have to.

If you must use a jQuery object because you want to attach events to the span or similar, than cloning is the way to go, though make sure you use clone(true, true) then to also clone the attached events.

You need to clone the element. Otherwise, after() will relocate the same element 3 times, which results in it being attached to only the last looped element.

$customElems.each(function () {
    $(this).wrap($spanOuter).after($spanInner.clone());
});

Demo: Fiddle

You might ask, "Why would wrap() work?" That's because 'wrap()' internally clones the element .

You're moving the same span from place to place. If you acted on all three divs at once, jquery will instead clone the span.

http://jsfiddle.net/a3ZK8/1/

var $customElems = $('.custom'),
    $spanOuter = $('<span class="outer"/>'),
    $spanInner = $('<span class="inner"/>');

$customElems.wrap($spanOuter).after($spanInner);

From the documentation for .after:

Important: If there is more than one target element, cloned copies of the inserted element will be created for each target except for the last one.

which means the last element will always get the original, while all other selected elements will get a clone. That's why when you acted on one element at a time, it simply moved the same span around.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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