可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an image tag inside of a table cell, that I'd love to move to another table cell, and have that movement animated.
The code looks something like this...
<td id="cell1"><img src="arrow.png" alt="Arrow"/></td>
<td id="cell2"></td>
I'd like to move "arrow.png" to "cell2", and have some kind of transition effect, preferably with JQuery.
Any ideas?
Thanks!
回答1:
This is actually quite difficult because you have to remove and add it to the DOM but keep its position. I think you're looking for something like this. Basically we don't animate either the arrow in #cell1
or #cell2
. We just create a new one in the body
-tag and animate that. That way we don't have to worry about the table cell positions because we can position relative to the document.
var $old = $('#cell1 img');
//First we copy the arrow to the new table cell and get the offset to the document
var $new = $old.clone().appendTo('#cell2');
var newOffset = $new.offset();
//Get the old position relative to document
var oldOffset = $old.offset();
//we also clone old to the document for the animation
var $temp = $old.clone().appendTo('body');
//hide new and old and move $temp to position
//also big z-index, make sure to edit this to something that works with the page
$temp
.css('position', 'absolute')
.css('left', oldOffset.left)
.css('top', oldOffset.top)
.css('zIndex', 1000);
$new.hide();
$old.hide();
//animate the $temp to the position of the new img
$temp.animate( {'top': newOffset.top, 'left':newOffset.left}, 'slow', function(){
//callback function, we remove $old and $temp and show $new
$new.show();
$old.remove();
$temp.remove();
});
I think this should point you in the right direction.
回答2:
@Pim Jager's answer is pretty good, however if you have object references to the original element they would break since the the original element was replaced with a clone
I came up with what I think is a slightly cleaner solution in that it only has a single clone that show up for animation then goes away, leaving the original in the new location.
function moveAnimate(element, newParent){
//Allow passing in either a jQuery object or selector
element = $(element);
newParent= $(newParent);
var oldOffset = element.offset();
element.appendTo(newParent);
var newOffset = element.offset();
var temp = element.clone().appendTo('body');
temp.css({
'position': 'absolute',
'left': oldOffset.left,
'top': oldOffset.top,
'z-index': 1000
});
element.hide();
temp.animate({'top': newOffset.top, 'left': newOffset.left}, 'slow', function(){
element.show();
temp.remove();
});
}
To use: moveAnimate('#ElementToMove', '#newContainer')
回答3:
You'll need to do this in two steps: (1) animation (2) rehoming.
The animation you can take care of with .animate(), as @Ballsacian points out. The rehoming can be accomplished with .html() - for the example above,
var arrowMarkup = $('#cell1').html(); //grab the arrow
$('#cell1').html(""); //delete it from the first cell
$('#cell2').html(arrowMarkup); //add it to the second cell
Of course, you'll have to complicate that code to integrate the animation. And this way of doing it won't cause the selection (I'm assuming you're selecting a table row?) to activate rows between the old selection and the new one, as the arrow passes by them. That'd be even more complex to achieve.
回答4:
I have extended one of the other answers a little further so that now you can pass an object as a third parameter which serves as a vehicle during the animation. For example, if you want to move some <li> from one <ul> to another, your <ul> likely has a certain class that gives the <li> its styling. So, it would really be handy to animate your <li> inside a temporary vehicle <ul> that provides for the same styling as either the source or the target <ul> of the animation:
//APPENDS AN ELEMENT IN AN ANIMATED FASHION
function animateAppendTo(el, where, float){
var pos0 = el.offset();
el.appendTo(where);
var pos1 = el.offset();
el.clone().appendTo(float ? float : 'body');
float.css({
'position': 'absolute',
'left': pos0.left,
'top': pos0.top,
'zIndex': 1000
});
el.hide();
float.animate(
{'top': pos1.top,'left': pos1.left},
'slow',
function(){
el.show();
float.remove();
});
}
回答5:
I was trying @Davy8's function which is quite good, but I found it quite jarring when the moved element snapped off the page at the start then back in at the end. The other page elements suddenly shifting interrupted an otherwise smooth animation, but this likely would depend on your page layout.
So this is a modified version of @Davy8's function, which should also smoothly shrink and grow space between parents.
function moveAnimate(element, newParent,
slideAnimationSpeed/*=800*/, spacerAnimationSpeed/*=600*/)
{
//Allow passing in either a jQuery object or selector
element = $(element);
newParent= $(newParent);
slideAnimationSpeed=slideAnimationSpeed||800;
spacerAnimationSpeed=spacerAnimationSpeed||600;
var oldOffset = element.offset();
var tempOutgoing=element.clone().insertAfter(element);
tempOutgoing.hide(); //Don't take up space yet so 'newOffset' can be calculated correctly
element.appendTo(newParent);
var newOffset = element.offset();
var tempMover = element.clone().appendTo('body');
tempMover.css({
'position': 'absolute',
'left': oldOffset.left,
'top': oldOffset.top,
'z-index': 1000,
'margin':0 //Necessary for animation alignment if the source element had margin
});
element.hide();
element.show(spacerAnimationSpeed).css('visibility', 'hidden'); //Smoothly grow space at the target
tempMover.animate({'top': newOffset.top, 'left': newOffset.left}, slideAnimationSpeed, function(){
element.css('visibility', 'visible');
tempMover.remove();
});
tempOutgoing.show().css('visibility', 'hidden');
tempOutgoing.hide(spacerAnimationSpeed, function(){ tempOutgoing.remove() }); //smoothly shrink space at the source
}
回答6:
If the animation doesn't have to be the thing moving, this question which uses fadeIn and fadeOut gives a simple, clean answer with no cloning and still conveys the motion quite well:
Re-ordering div positions with jQuery?
回答7:
For anyone still viewing this, I found the provided examples didn't fit exactly what I wanted and they didn't account for margins, so here's my version:
jQuery.fn.extend({
moveElement : function (newParent, speed, after) {
var origEl = $(this);
var moveToEl = $(newParent);
var oldOffset = origEl.offset();
var temp = origEl.clone().appendTo('body');
temp.css({
'position' : 'absolute',
'left' : parseInt(oldOffset.left) - parseInt(origEl.css('margin-left')),
'margin' : origEl.css('margin'),
'top' : oldOffset.top,
'z-index' : 1000,
'height' : moveToEl.innerHeight(),
'width' : moveToEl.innerWidth()
});
var blankEl = $('<div></div>').css({
height : moveToEl.innerHeight(),
margin : moveToEl.css('margin'),
position : 'relative',
width : moveToEl.innerWidth()
});
if (after) {
origEl.insertAfter(moveToEl);
blankEl.insertAfter(newParent);
}
else {
origEl.insertBefore(moveToEl);
blankEl.insertBefore(newParent);
}
origEl.hide();
var newOffset = blankEl.offset();
temp.animate({
'top' : blankEl.offset().top - parseInt(moveToEl.css('margin-top')),
'left' : newOffset.left - parseInt(moveToEl.css('margin-left'))
}, speed, function () {
blankEl.remove();
origEl.show();
temp.remove();
});
}
});
Move an element before another: $('.elementToFind').moveElement('.targetElement', 1000);
Move an element after another: $('.elementToFind').moveElement('.targetElement', 1000, 'after');
回答8:
JQuery http://docs.jquery.com/Downloading_jQuery
JQuery Effects http://docs.jquery.com/Effects/animate#paramsoptions
Example
$("#go1").click(function(){
$("#block1").animate( { width:"90%" }, { queue:false, duration:3000 } )
.animate( { fontSize:"24px" }, 1500 )
.animate( { borderRightWidth:"15px" }, 1500);
});