起因
目前想做一个拖拽排序且带动画的功能,经过考虑和参考后,发现大部分解决方法都是将元素改为绝对定位,之后通过 transition 或别的方式插值处理 left 和 top,于是测试后这种方式。
问题
但编码中发现一个问题,使用 js 或 jQuery 遍历并修改元素css时,会出现所有元素被赋予第一个元素的CSS样式。
当不修改CSS时,打印的css变量均正常,但如果修改,则后续所有变量值都会变成第一次的值。
不知该问题为什么引起又如何解决?
Document* {
box-sizing: border-box;
}
.container {
display: flex;
width: 100%;
flex-wrap: wrap;
position: relative;
}
.box {
flex: 0 0 25%;
border: 1px solid #999;
margin-top: 10px;
}
$(document).ready(function () {
$('.box').each(function () {
var css = {
'position': 'absolute',
'left': $(this)[0].offsetLeft,
'top': $(this)[0].offsetTop,
'width': $(this)[0].offsetWidth,
'height': $(this)[0].offsetHeight
};
console.log(css);
$(this).removeClass('box');
// 如果执行下面一行,则所有的 css 内容都会变成第一个元素的值
// position:absolute;left: 0px; top: 10px;width: 226px;height: 23px
$(this).css(css);
});
});
原因与解决方案
几天后我回顾了此问题,将自己最终的理解重新整理。
该问题的重点,在于jQuery的css()方法或javascript修改style都会立即触发重排。
修改css并移除box后,浏览器已经立即将第二项移动到了第一项的位置。
每次修改css后都会触发重排,所以解决方案就是在取到所有css数据后(循环结束后),再修改样式。
也就是:
$('.box').each(function () {
var css = {
'position': 'absolute',
'left': $(this)[0].offsetLeft,
'top': $(this)[0].offsetTop,
'width': $(this)[0].offsetWidth,
'height': $(this)[0].offsetHeight
};
var that = $(this);
setTimeout(function () {
that.css(css);
that.removeClass('box');
}, 0);
});