AMasonry

AMasonry is a virtualized masonry / waterfall layout for rendering large datasets efficiently. You supply items, a colWidth, and an itemHeightGetter function that returns each item’s pixel height; the default slot renders each cell with { data, position, colWidth } scope.

Import

import { Masonry } from '@any-design/anyui/vue';
// React:  import { Masonry } from '@any-design/anyui/react';
// Svelte: import { Masonry } from '@any-design/anyui/svelte';

Basic usage

<template>
  <div class="masonry-preview">
    <AMasonry
      :items="items"
      :col-width="180"
      :item-height-getter="(item) => item.height"
      :gap="12"
      scroll-event-target=".masonry-preview"
      fit
    >
      <template #default="{ data }">
        <div class="masonry-card" :style="{ height: data.height + 'px' }">
          <strong>{{ data.title }}</strong>
        </div>
      </template>
    </AMasonry>
  </div>
</template>

<script setup>
const items = Array.from({ length: 80 }, (_, i) => ({
  id: i,
  title: `Item ${i}`,
  height: 112 + (i % 5) * 34,
}));
</script>

<style scoped>
.masonry-preview {
  max-height: 360px;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--a-radius-lg, 18px);
  background: var(--bg-semi-light, var(--bg));
}

.masonry-card {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 14px;
  border-radius: var(--a-radius, 14px);
  background: linear-gradient(140deg, var(--primary), var(--secondary));
  color: var(--text-btn, #fff);
  box-shadow: var(--a-shadow-sm, 0 4px 12px var(--shadow-6));
}

</style>

Examples

Fixed column count

Set col to force a specific number of columns instead of deriving it from colWidth.

<template>
  <AMasonry :items="items" :col="3" :col-width="180" :item-height-getter="(i) => i.height">
    <template #default="{ data }">
      <div class="masonry-card" :style="{ height: data.height + 'px' }">{{ data.title }}</div>
    </template>
  </AMasonry>
</template>

Fit items to column width

fit stretches each item to fill the computed column width.

<template>
  <AMasonry :items="items" :col-width="240" :item-height-getter="(i) => i.height" fit>
    <template #default="{ data }">
      <div class="masonry-card" :style="{ height: data.height + 'px' }">{{ data.title }}</div>
    </template>
  </AMasonry>
</template>

Props

Prop Type Default Description
items Array undefined Required. Items to render.
itemHeightGetter (item) => number undefined Required. Returns the pixel height of an item.
colWidth Number undefined Required. Column width in px.
col Number 0 Force a column count (0 = auto).
gap Number 16 Gap (px) between items.
fit Boolean false Stretch items to column width.
rowsPerSection Number 3 Rows per recycled section.
groupSize Number 100 Render group size.
additionalDistance Number 1600 Extra render distance (px).
recycleNode Boolean false Enable DOM node recycling.
scrollDebounceTime / scrollThrottleTime Number 200 / 100 Scroll event tuning.
resizeThrottleTime / resizeDebounceTime Number 100 / 200 Resize event tuning.
scrollEventTarget String undefined Selector for a custom scroll container.

Slots

Slot Props Description
default { data, position, colWidth } Item template.

AMasonry

AMasonry 是面向大数据量的虚拟化瀑布流布局。你需要提供 itemscolWidth 以及返回每个项目像素高度的 itemHeightGetter 函数;默认插槽渲染每个单元格,作用域为 { data, position, colWidth }

引入

import { Masonry } from '@any-design/anyui/vue';
// React:  import { Masonry } from '@any-design/anyui/react';
// Svelte: import { Masonry } from '@any-design/anyui/svelte';

基础用法

<template>
  <div class="masonry-preview">
    <AMasonry
      :items="items"
      :col-width="180"
      :item-height-getter="(item) => item.height"
      :gap="12"
      scroll-event-target=".masonry-preview"
      fit
    >
      <template #default="{ data }">
        <div class="masonry-card" :style="{ height: data.height + 'px' }">
          <strong>{{ data.title }}</strong>
        </div>
      </template>
    </AMasonry>
  </div>
</template>

<script setup>
const items = Array.from({ length: 80 }, (_, i) => ({
  id: i,
  title: `项目 ${i}`,
  height: 112 + (i % 5) * 34,
}));
</script>

<style scoped>
.masonry-preview {
  max-height: 360px;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--a-radius-lg, 18px);
  background: var(--bg-semi-light, var(--bg));
}

.masonry-card {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 14px;
  border-radius: var(--a-radius, 14px);
  background: linear-gradient(140deg, var(--primary), var(--secondary));
  color: var(--text-btn, #fff);
  box-shadow: var(--a-shadow-sm, 0 4px 12px var(--shadow-6));
}

</style>

示例

固定列数

设置 col 强制指定列数,而非根据 colWidth 自动计算。

<template>
  <AMasonry :items="items" :col="3" :col-width="180" :item-height-getter="(i) => i.height">
    <template #default="{ data }">
      <div class="masonry-card" :style="{ height: data.height + 'px' }">{{ data.title }}</div>
    </template>
  </AMasonry>
</template>

拉伸到列宽

fit 将每个项目拉伸以填满计算出的列宽。

<template>
  <AMasonry :items="items" :col-width="240" :item-height-getter="(i) => i.height" fit>
    <template #default="{ data }">
      <div class="masonry-card" :style="{ height: data.height + 'px' }">{{ data.title }}</div>
    </template>
  </AMasonry>
</template>

属性

属性 类型 默认值 说明
items Array undefined 必填。要渲染的数据。
itemHeightGetter (item) => number undefined 必填。返回单个项目的像素高度。
colWidth Number undefined 必填。列宽(px)。
col Number 0 强制列数(0 = 自动)。
gap Number 16 项目间距(px)。
fit Boolean false 将项目拉伸到列宽。
rowsPerSection Number 3 每个回收区段的行数。
groupSize Number 100 渲染分组大小。
additionalDistance Number 1600 额外渲染距离(px)。
recycleNode Boolean false 开启 DOM 节点回收。
scrollDebounceTime / scrollThrottleTime Number 200 / 100 滚动事件调参。
resizeThrottleTime / resizeDebounceTime Number 100 / 200 resize 事件调参。
scrollEventTarget String undefined 自定义滚动容器的选择器。

插槽

插槽 作用域参数 说明
default { data, position, colWidth } 项目模板。
Item 0
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Show code
<!-- Demo 1 -->
<template>
  <div class="masonry-preview">
    <AMasonry
      :items="items"
      :col-width="180"
      :item-height-getter="(item) => item.height"
      :gap="12"
      scroll-event-target=".masonry-preview"
      fit
    >
      <template #default="{ data }">
        <div class="masonry-card" :style="{ height: data.height + 'px' }">
          <strong>{{ data.title }}</strong>
        </div>
      </template>
    </AMasonry>
  </div>
</template>

<script setup>
const items = Array.from({ length: 80 }, (_, i) => ({
  id: i,
  title: `Item ${i}`,
  height: 112 + (i % 5) * 34,
}));
</script>

<style scoped>
.masonry-preview {
  max-height: 360px;
  overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--a-radius-lg, 18px);
  background: var(--bg-semi-light, var(--bg));
}

.masonry-card {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 14px;
  border-radius: var(--a-radius, 14px);
  background: linear-gradient(140deg, var(--primary), var(--secondary));
  color: var(--text-btn, #fff);
  box-shadow: var(--a-shadow-sm, 0 4px 12px var(--shadow-6));
}

</style>
EN
中文