起因
目前想做一个拖拽排序且带动画的功能,经过考虑和参考后,发现大部分解决方法都是将元素改为绝对定位,之后通过 transition 或别的方式插值处理 left 和 top,于是测试后这种方式。
问题
但编码中发现一个问题,使用 js 或 jQuery 遍历并修改元素css时,会出现所有元素被赋予第一个元素的CSS样式。
当不修改CSS时,打印的css变量均正常,但如果修改,则后续所有变量值都会变成第一次的值。
不知该问题为什么引起又如何解决?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
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;
}
</style>
</head>
<body>
<div class="container">
<div class="box" draggable="true">1</div>
<div class="box" draggable="true">2</div>
<div class="box" draggable="true">3</div>
<div class="box" draggable="true">4</div>
<div class="box" draggable="true">5</div>
<div class="box" draggable="true">6</div>
<div class="box" draggable="true">7</div>
<div class="box" draggable="true">8</div>
<div class="box" draggable="true">9</div>
<div class="box" draggable="true">10</div>
<div class="box" draggable="true">11</div>
<div class="box" draggable="true">12</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$(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);
});
});
</script>
</body>
</html>
原因与解决方案
几天后我回顾了此问题,将自己最终的理解重新整理。
该问题的重点,在于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);
});
你有10个盒子累起来了,你决定抽调最后一个把它粘在墙上,然后其余9个都掉下来了, 所以每次你获取的最后一个盒子位置总是一样的, 因为他们总是在最底部.
解决方案就是不要立即抽调最后一个盒子,把尺寸都测量完后在执行抽出的操作.