两列砌体网格:如何在保持顺序的同时将 div 堆成两列(在我的例子中是 Vue3)?

Two column masonry grid: How to pile divs into two columns while preserving their order (Vue3 in my case)?

在我的 VueJS 3 应用程序中,我想将 div 的集合堆叠在一起,形成两列。 div 已编号,它们的顺序应垂直保留。换句话说:当从上到下读取 div 个数字时,应该读取:1, 2, 3, 4, 5 ...

请参阅 this codepen 以获得所需结果的图形说明。

或者看下面的代码。

<!DOCTYPE html>
<html lang="en">

<head>
<style>

.boxes {
  width: 640px;
  background-color: rgb(210, 166, 252);
  overflow: auto;
}

.box {
  width: 300px;
  background-color: blueviolet;
  margin: 10px;
  padding: 16px;
  box-sizing: border-box;
}

.left {
  float: left;
  clear: left;
}

.right {
  float: right;
  clear: right;
}

h3 {
  text-align: center;
  margin: 0;
}

</style>
</head>

<body>
  
  <div class="boxes">
    <div class="box left"><h3>1.</h3> Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium, blanditiis unde ab ullam nesciunt deleniti vitae, temporibus deserunt vel qui reprehenderit eveniet quas sapiente corrupti fuga eum sint ducimus aspernatur aliquid tenetur velit quaerat. Culpa perferendis error, ad a nesciunt voluptatibus laborum maiores dolor, dolorum maxime assumenda quam odit atque.</div>
    <div class="box right"><h3>2.</h3> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Quos soluta beatae ipsam assumenda nihil dolor, ratione a quas vitae perferendis doloribus perspiciatis iure! Aliquam, ut.</div>
    <div class="box right"><h3>3.</h3> Lorem ipsum dolor sit amet consectetur adipisicing elit. Laudantium quasi cupiditate doloremque saepe sed, nisi et nostrum at, illo est ipsa doloribus nulla soluta consequuntur ullam sapiente debitis quam. Odio?</div>
    <div class="box left"><h3>4.</h3> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolorum aspernatur et, voluptas dolores quidem quasi. Lorem ipsum dolor, sit amet consectetur adipisicing elit. Nam eveniet earum, perferendis quasi blanditiis veritatis nobis vel modi excepturi molestias, sint debitis dolor aspernatur inventore repellendus ullam libero non dolores in sed, quas illo incidunt nulla magni! Neque, optio delectus! Lorem ipsum, dolor sit amet consectetur adipisicing elit. Omnis eos doloribus aliquam sapiente assumenda? Incidunt, vero fugiat. Qui excepturi ratione, labore pariatur saepe nobis a quibusdam ad incidunt, eius iusto!</div>
    <div class="box right"><h3>5.</h3> Lorem ipsum, dolor sit amet consectetur adipisicing elit. Soluta neque distinctio recusandae eveniet necessitatibus sint magni omnis dolorem voluptatibus dolore repellat adipisci, blanditiis doloremque reiciendis harum voluptas incidunt fugit dolores ipsam placeat expedita debitis. Dignissimos reprehenderit quia totam, debitis aperiam sed iure.</div>
    <div class="box right"><h3>6.</h3> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Accusantium saepe a eum pariatur officiis adipisci eligendi, minus ipsam.</div>
    <div class="box left"><h3>7.</h3> Lorem ipsum dolor sit amet consectetur adipisicing elit. Quasi quisquam earum dicta ipsum repellendus voluptate animi quis ea eaque enim culpa reprehenderit beatae, deserunt ab consequuntur ratione libero?</div>
    <div class="box right"><h3>8.</h3> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolorum aspernatur et, voluptas dolores quidem quasi.</div>
    <div class="box left"><h3>9.</h3> Lorem ipsum, dolor sit amet consectetur adipisicing elit. Soluta neque distinctio recusandae eveniet necessitatibus sint magni omnis dolorem voluptatibus dolore repellat adipisci, blanditiis doloremque reiciendis harum voluptas incidunt fugit dolores ipsam placeat expedita debitis. Dignissimos reprehenderit quia totam, debitis aperiam sed iure.</div>
    <div class="box right"><h3>10.</h3> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolorum aspernatur et, voluptas dolores quidem quasi.</div>
    <div class="box right"><h3>11.</h3> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolorum aspernatur et, voluptas dolores quidem quasi.</div>
  </div>
</body>

</html>

为了获得我的 div 的正确顺序,我手动为每个 div 分配了 .left 或 .right。我想自动化这个过程。

在我的 Vue 应用程序中,一个 v-for 循环遍历一个包含所有 div 内容的数组。在上面的例子中省略了 Vue 部分,以使示例代码更简单。

我已经尝试过的:

我曾尝试在 Vue 中使用动态分配的 类 并在 运行 期间使用 $refs 测量每列的高度,但我无法使其工作。

vanilla JS apporach 可能是一个解决方案,但我想知道如何以 Vue 方式执行此操作,最好是。

谢谢。

通过在 forEach 循环的每次迭代期间检查 div 容器的高度,我能够编写一个简短的解决方案。

见下文或见Codepen

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

<style >

#boxes {
  width: 640px;
  background-color: rgb(210, 166, 252);
  overflow: auto;
}

.box {
  width: 300px;
  background-color: blueviolet;
  margin: 10px;
  padding: 16px;
  box-sizing: border-box;
}

.left {
  float: left;
  clear: left;
}

.right {
  float: right;
  clear: right;
}

</style>

</head>
<body>
  
  <div id="boxes">

  </div>


<script>


let boxesArray = [
  {id: 0, name: '1. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 1, name: '2. Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 2, name: '3. Hello Hello Hello Hello Hello Hello Hello'},
  {id: 3, name: '4. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 4, name: '5. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 5, name: '6. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 6, name: '7. Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 7, name: '8. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
  {id: 8, name: '9. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello '},
  {id: 9, name: '10. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'}]

boxesArray.forEach(item => {
  
  let boxes = document.getElementById("boxes")
  let lastIteration = boxes.offsetHeight
  let side = null
  let classesOfLastAdded = boxes.lastChild

  if (!globalThis.masonrySwitchHelper) {
    globalThis.masonrySwitchHelper = false
  }

  function makeBox (side) {
    let node = document.createElement("DIV")
    node.className += "box"
    node.className += " " + side
    let textnode = document.createTextNode(item.name)
    node.appendChild(textnode)
    boxes.appendChild(node)
  }

  if (classesOfLastAdded.className === 'box left' && globalThis.masonrySwitchHelper === true) {
    makeBox('right')
  }
  else if (classesOfLastAdded.className === 'box right' && globalThis.masonrySwitchHelper === true) {
    makeBox('left')
  }
  else if (classesOfLastAdded.className === 'box left' && globalThis.masonrySwitchHelper === false) {
    makeBox('left')
  }
  else if (classesOfLastAdded.className === 'box right' && globalThis.masonrySwitchHelper === false) {
    makeBox('right')
  }
  else {
    makeBox('left')
  }

 
  let thisIteration = boxes.offsetHeight

  if (thisIteration > lastIteration) {
    globalThis.masonrySwitchHelper = true
  }
  else {
    globalThis.masonrySwitchHelper = false
  }

})

</script>

</body>
</html>

JavaScript 代码可以更简洁和健壮,但我遇到了一些奇怪的错误,所以我解决了这个问题。

我不想在这个 Stack Overflow 中留下任何遗留问题 post,所以我将分享我最终在 Vue 中使用的代码。

与我 posted 的 Vanilla JS 解决方案相比,我在此 VueJS 解决方案中采用了稍微不同的方法。对于每个盒子,我比较了前一个盒子底部的高度和所有盒子都创建后的那个之前的高度。而不是在盒子的迭代创建过程中检查盒子容器底部的高度。

参见 Codepen 或下面的代码。

<!DOCTYPE html>
<html lang="en">
<head>
<style>
#boxes {
  width: 640px;
  background-color: rgb(210, 166, 252);
  overflow: auto;
}

.box {
  width: 300px;
  background-color: blueviolet;
  margin: 10px;
  padding: 16px;
  box-sizing: border-box;
}

.left {
  float: left;
  clear: left;
}

.right {
  float: right;
  clear: right;
}
</style>
</head>
<body>
  
  <div id="app">
    <div id="boxes" ref="boxes">
      <div v-for="box in boxes" class="box">

        {{ box.name }}

      </div>
    </div>
  </div>

  <script src="https://unpkg.com/vue@3"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

  <script>

    Vue.createApp({

      data () {
        return {
          boxes: [
            {id: 0, name: '1. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 1, name: '2. Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 2, name: '3. Hello Hello Hello Hello Hello Hello Hello'},
            {id: 3, name: '4. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 4, name: '5. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 5, name: '6. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 6, name: '7. Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 7, name: '8. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'},
            {id: 8, name: '9. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello '},
            {id: 9, name: '10. Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello'}
          ]
        }
      },
      mounted () {
        let allBoxes = document.querySelectorAll('.box')

        let firstBox = allBoxes[0]
        firstBox.classList.add('left')

        let secondBox = allBoxes[1]
        secondBox.classList.add('right')


        for (let i = 2; i < allBoxes.length; i++) {

          let previousPrevious = allBoxes[i-2]
          let previous = allBoxes[i-1]

          let heightOfPreviousPrevious = previousPrevious.getBoundingClientRect().bottom
          let heightOfPrevious = previous.getBoundingClientRect().bottom

          let sideOfPrevious = null
          let switchedSide = null

          if ( previous.classList.contains('right') ) {
            sideOfPrevious = 'right'
            switchedSide = 'left'
          }
          else if ( previous.classList.contains('left') ) {
            sideOfPrevious = 'left'
            switchedSide = 'right'
          }

          if (heightOfPrevious < heightOfPreviousPrevious) {
            allBoxes[i].classList.add(sideOfPrevious)
          }
          else {
            allBoxes[i].classList.add(switchedSide)
          }
        }
      }
    })
    .mount('#app')

  </script>

</body>
</html>