如何以尽可能紧凑的方式计算列数,使得每行都具有全部偶数或全部奇数个项目?

问题描述 投票:0回答:1

我想布局类似于 this:

的 unicode 字形

显示的集合中可能有 13 到 100 个项目(字母表、辅音字母、附音表、音节文字等),因此可能有一组包含 99 个项目的集合,或者一组包含 16 个项目的集合,等等。

如何才能最漂亮(并且自动)布局元素(以便响应时也很好)?这是我默认使用 Flexbox 的内容:

enter image description here

每个项目都有固定的高度,宽度是响应式的(但每个元素都相同)。

目标是让每一行都有偶数或奇数个项目。这样,所有垂直列都会对齐(并且它不会像我的动画 gif 那样,偶数/奇数行混合在一起)。

  1. 是否可以做一些数学公式来计算“每行需要 5 个项目,除了最后一行将有 3 个(或 1 个)”?给定一些总数,例如 99?

你会怎么做?

我有一个 React 组件,它的 Flexbox 布局类似于

<Grid minWidth={96} gap={8} maxColumns={5} breakpoints={[5, 3, 1]} />
,其中
breakpoints
是每行允许的项目数,
maxColumns
是最大列数 (断点/maxColumn 有点多余,你可以定义或者,也许我稍后会清理它)。所有这些信息可能无关紧要,但只是指出以防万一,这是我的响应式网格组件。

我怎样才能以某种方式将我的总数除以x以确定它应该是偶数行还是奇数行,然后将

maxColumns
breakpoints
设置为“最紧凑”的值?例如:

  • 如果是 26 个元素,看起来最好是 6 行,每行 4 个,然后是 1 行,每行 2 个。 - 如果是 27 个元素

它的“美”可能是主观的,并没有明确的规则来定义什么是最美的。只是寻找任何不容易在末尾留下孤立的单个节点,然后在所有其他行上有 7 个项目的东西。理想情况下我们有:

  • 第 3 列和第 7 列之间。
  • 最后一行必须与之前所有行中的项目数量相同,或者不少于
    maxRowCount - 2
    (因此,如果所有行都有 7,则最后一行只能有 5 或 7,或者如果所有行都有 5,则最后一行行只能有 3 或 5 等)。
  • 行项目有一个
    minWidth: 96px
    ,并且会增长以填充空间。一旦我们掌握了这项工作的基础知识,我就可以弄清楚如何让事情做出响应,但假设存在
    containerWidth

所以在我的脑海里,说我们有

containerWidth === 700px
。然后,
700/96 == 7+
,所以每行可能有 7 个。例如,如果我们有 99 个项目,则
99 % 7 == 1
,因此
7
不起作用,因为最后一行有 1 个项目。
6
不起作用,因为
99
是偶数,所以尝试
5
99 % 5 == 4
,这是行不通的,因为
4
是偶数。所以尝试一下
3
99 % 3 == 0
,这样就可以按原样工作,使用它!

你会如何实现这样的事情?

javascript math
1个回答
0
投票

这样的事情看起来是正确的,但是我正确解决了吗?

console.log(
  99,
  calculateColumns({ totalCount: 99, itemWidth: 96, containerWidth: 700 })
);
console.log(
  98,
  calculateColumns({ totalCount: 98, itemWidth: 96, containerWidth: 700 })
);
console.log(
  97,
  calculateColumns({ totalCount: 97, itemWidth: 96, containerWidth: 700 })
);
console.log(
  96,
  calculateColumns({ totalCount: 96, itemWidth: 96, containerWidth: 700 })
);
console.log(
  95,
  calculateColumns({ totalCount: 95, itemWidth: 96, containerWidth: 700 })
);
console.log(
  94,
  calculateColumns({ totalCount: 94, itemWidth: 96, containerWidth: 700 })
);
console.log(
  93,
  calculateColumns({ totalCount: 93, itemWidth: 96, containerWidth: 700 })
);

function calculateColumns({ totalCount, itemWidth, containerWidth }) {
  let max = Math.min(Math.floor(containerWidth / itemWidth), 7)
  while (max > 3) {
    const maxIsEven = isEven(max)
    const remainder = totalCount % max
    const remainderIsEven = isEven(remainder)
    if (maxIsEven && remainderIsEven) {
      const diff = max - remainder
      if (diff <= 2) {
        return max
      }
    } else if (!maxIsEven && (!remainderIsEven || !remainder)) {
      const diff = max - remainder
      if (diff <= 2) {
        return max;
      }
    } else {
      // one is even, one is odd
    }
    max--
  }
  return max
}

function isEven(n) {
  return n % 2 === 0
}

© www.soinside.com 2019 - 2024. All rights reserved.