鍍金池/ 問答/Linux  HTML/ 遍歷DOM并修改CSS時,為何后續(xù)元素的樣式都會變成第一個元素的樣式?

遍歷DOM并修改CSS時,為何后續(xù)元素的樣式都會變成第一個元素的樣式?

起因

目前想做一個拖拽排序且?guī)赢嫷墓δ?,?jīng)過考慮和參考后,發(fā)現(xiàn)大部分解決方法都是將元素改為絕對定位,之后通過 transition 或別的方式插值處理 left 和 top,于是測試后這種方式。

問題

但編碼中發(fā)現(xiàn)一個問題,使用 js 或 jQuery 遍歷并修改元素css時,會出現(xiàn)所有元素被賦予第一個元素的CSS樣式。
當(dāng)不修改CSS時,打印的css變量均正常,但如果修改,則后續(xù)所有變量值都會變成第一次的值。
不知該問題為什么引起又如何解決?

<!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');
                // 如果執(zhí)行下面一行,則所有的 css 內(nèi)容都會變成第一個元素的值
                // position:absolute;left: 0px; top: 10px;width: 226px;height: 23px
                $(this).css(css);
            });
        });
    </script>
</body>

</html>

原因與解決方案

幾天后我回顧了此問題,將自己最終的理解重新整理。

該問題的重點,在于jQuerycss()方法或javascript修改style都會立即觸發(fā)重排。

修改css并移除box后,瀏覽器已經(jīng)立即將第二項移動到了第一項的位置。

每次修改css后都會觸發(fā)重排,所以解決方案就是在取到所有css數(shù)據(jù)后(循環(huán)結(jié)束后),再修改樣式。
也就是:

$('.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個盒子累起來了,你決定抽調(diào)最后一個把它粘在墻上,然后其余9個都掉下來了, 所以每次你獲取的最后一個盒子位置總是一樣的, 因為他們總是在最底部.

解決方案就是不要立即抽調(diào)最后一個盒子,把尺寸都測量完后在執(zhí)行抽出的操作.

function queueUpdate($el, css) {
  setTimeout(function () {
    $el.css(css)
  }, 0)
}

$(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
    };
    $(this).removeClass('box');
    
    // 如果執(zhí)行下面一行,則所有的 css 內(nèi)容都會變成第一個元素的值
    // position:absolute;left: 0px; top: 10px;width: 226px;height: 23px
    queueUpdate($(this), css)
  });
});
2018年6月19日 19:53
編輯回答
痞性

執(zhí)行$(this).css(css);這個后你的$(this)[0].offsetLeft,這些都發(fā)生變化了

2018年8月28日 16:54