Guides
Grid Types
MasonryInfiniteGrid
MasonryInfiniteGrid is a grid that stacks items with the same width as a stack of bricks. Adjust the width of all images to the same size, find the lowest height column, and insert a new item.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { MasonryInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new MasonryInfiniteGrid(".container", {
gap: 5,
});
ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();
import * as React from "react";
import { MasonryInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <MasonryInfiniteGrid
className="container"
gap={5}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>;
}
<template>
<masonry-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</masonry-infinite-grid>
</template>
<script lang="ts">
import { MasonryInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
MasonryInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<template>
<masonry-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</masonry-infinite-grid>
</template>
<script lang="ts">
import { MasonryInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
MasonryInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<div NgxMasonryInfiniteGrid
class="container"
[gap]="5"
[items]="items"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<div class="item" *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" />
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
</div>
import { Component, Input } from '@angular/core';
import { OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
groupBy(_: any, item: any) {
return item.groupKey;
}
trackBy(_: any, item: any) {
return item.key;
}
onRequestAppend(e: OnRequestAppend) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...this.getItems(nextGroupKey, 10),
];
}
}
<script>
import { MasonryInfiniteGrid } from "@egjs/svelte-infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<MasonryInfiniteGrid
class="container"
gap={5}
{items}
on:requestAppend={({ detail: e }) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
items = [...items, ...getItems(nextGroupKey, 10)];
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{/each}
</MasonryInfiniteGrid>
JustifiedInfiniteGrid
'justified' is a printing term with the meaning that 'it fits in one row wide'. JustifiedGrid is a grid that the item is filled up on the basis of a line given a size.
- If 'data-grid-inline-offset' or 'data-grid-content-offset' are set for item element, the ratio is maintained except for the offset value.
- If 'data-grid-maintained-target' is set for an element whose ratio is to be maintained, the item is rendered while maintaining the ratio of the element.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { JustifiedInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" data-grid-maintained-target="true"/>
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new JustifiedInfiniteGrid(".container", {
gap: 5,
});
ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();
import * as React from "react";
import { JustifiedInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs" data-grid-maintained-target="true"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <JustifiedInfiniteGrid
className="container"
gap={5}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</JustifiedInfiniteGrid>;
}
<template>
<justified-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs" data-grid-maintained-target="true"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</justified-infinite-grid>
</template>
<script lang="ts">
import { JustifiedInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
JustifiedInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<template>
<justified-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs" data-grid-maintained-target="true"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</justified-infinite-grid>
</template>
<script lang="ts">
import { JustifiedInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
JustifiedInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<div NgxJustifiedInfiniteGrid
class="container"
[gap]="5"
[items]="items"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<div class="item" *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" data-grid-maintained-target="true"/>
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
</div>
import { Component, Input } from '@angular/core';
import { OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
groupBy(_: any, item: any) {
return item.groupKey;
}
trackBy(_: any, item: any) {
return item.key;
}
onRequestAppend(e: OnRequestAppend) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...this.getItems(nextGroupKey, 10),
];
}
}
<script>
import { JustifiedInfiniteGrid } from "@egjs/svelte-infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<JustifiedInfiniteGrid
class="container"
gap={5}
{items}
on:requestAppend={({ detail: e }) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
items = [...items, ...getItems(nextGroupKey, 10)];
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs" data-grid-maintained-target="true"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{/each}
</JustifiedInfiniteGrid>
JustifiedInfiniteGrid (Stretch)
stretch
is possible to basically break the proportion of the item and stretch the inline size to fill the container. If you set the sizeRange
range narrowly, you can stretch well.
stretchRange
: If-
,+
, or%
are added as a string value, it is a relative value to the original size. If it is a number value, the stretch range can be set as an absolute value. Ifdata-grid-min-stretch
anddata-grid-max-stretch
are set in the Element or JSX of each item, they will be applied first.passUnstretchRow
: Items placed in the last row are not stretched and are drawn maintaining their proportions. When using InfiniteGrid, it is calculated and re-rendered as follows:
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { JustifiedInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new JustifiedInfiniteGrid(".container", {
gap: 5,
stretch: true,
passUnstretchRow: true,
sizeRange: [228,228],
stretchRange: [144,320],
});
ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();
import * as React from "react";
import { JustifiedInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <JustifiedInfiniteGrid
className="container"
gap={5}
stretch={true}
passUnstretchRow={true}
sizeRange={[228,228]}
stretchRange={[144,320]}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</JustifiedInfiniteGrid>;
}
<template>
<justified-infinite-grid
class="container"
v-bind:gap="5"
v-bind:stretch="true"
v-bind:passUnstretchRow="true"
v-bind:sizeRange="[228,228]"
v-bind:stretchRange="[144,320]"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</justified-infinite-grid>
</template>
<script lang="ts">
import { JustifiedInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
JustifiedInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<template>
<justified-infinite-grid
class="container"
v-bind:gap="5"
v-bind:stretch="true"
v-bind:passUnstretchRow="true"
v-bind:sizeRange="[228,228]"
v-bind:stretchRange="[144,320]"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</justified-infinite-grid>
</template>
<script lang="ts">
import { JustifiedInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
JustifiedInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<div NgxJustifiedInfiniteGrid
class="container"
[gap]="5"
[stretch]="true"
[passUnstretchRow]="true"
[sizeRange]="[228,228]"
[stretchRange]="[144,320]"
[items]="items"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<div class="item" *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" />
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
</div>
import { Component, Input } from '@angular/core';
import { OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
groupBy(_: any, item: any) {
return item.groupKey;
}
trackBy(_: any, item: any) {
return item.key;
}
onRequestAppend(e: OnRequestAppend) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...this.getItems(nextGroupKey, 10),
];
}
}
<script>
import { JustifiedInfiniteGrid } from "@egjs/svelte-infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<JustifiedInfiniteGrid
class="container"
gap={5}
stretch={true}
passUnstretchRow={true}
sizeRange={[228,228]}
stretchRange={[144,320]}
{items}
on:requestAppend={({ detail: e }) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
items = [...items, ...getItems(nextGroupKey, 10)];
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{/each}
</JustifiedInfiniteGrid>
FrameInfiniteGrid
'Frame' is a printing term with the meaning that 'it fits in one row wide'. FrameGrid is a grid that the item is filled up on the basis of a line given a size.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { FrameInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new FrameInfiniteGrid(".container", {
gap: 5,
frame: [[1,1,2,3,3],[1,1,4,4,5]],
});
ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();
import * as React from "react";
import { FrameInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <FrameInfiniteGrid
className="container"
gap={5}
frame={[[1,1,2,3,3],[1,1,4,4,5]]}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</FrameInfiniteGrid>;
}
<template>
<frame-infinite-grid
class="container"
v-bind:gap="5"
v-bind:frame="[[1,1,2,3,3],[1,1,4,4,5]]"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</frame-infinite-grid>
</template>
<script lang="ts">
import { FrameInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
FrameInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<template>
<frame-infinite-grid
class="container"
v-bind:gap="5"
v-bind:frame="[[1,1,2,3,3],[1,1,4,4,5]]"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</frame-infinite-grid>
</template>
<script lang="ts">
import { FrameInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
FrameInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<div NgxFrameInfiniteGrid
class="container"
[gap]="5"
[frame]="[[1,1,2,3,3],[1,1,4,4,5]]"
[items]="items"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<div class="item" *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" />
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
</div>
import { Component, Input } from '@angular/core';
import { OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
groupBy(_: any, item: any) {
return item.groupKey;
}
trackBy(_: any, item: any) {
return item.key;
}
onRequestAppend(e: OnRequestAppend) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...this.getItems(nextGroupKey, 10),
];
}
}
<script>
import { FrameInfiniteGrid } from "@egjs/svelte-infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<FrameInfiniteGrid
class="container"
gap={5}
frame={[[1,1,2,3,3],[1,1,4,4,5]]}
{items}
on:requestAppend={({ detail: e }) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
items = [...items, ...getItems(nextGroupKey, 10)];
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{/each}
</FrameInfiniteGrid>
PackingInfiniteGrid
The PackingGrid is a grid that shows the important items bigger without sacrificing the weight of the items.
- Rows and columns are separated so that items are dynamically placed within the horizontal and vertical space rather than arranged in an orderly fashion.
- If
sizeWeight
is higher thanratioWeight
, the size of items is preserved as much as possible. - Conversely, if
ratioWeight
is higher thansizeWeight
, the ratio of items is preserved as much as possible.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { PackingInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new PackingInfiniteGrid(".container", {
gap: 5,
});
ig.on("requestAppend", (e) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
ig.renderItems();
import * as React from "react";
import { PackingInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <PackingInfiniteGrid
className="container"
gap={5}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</PackingInfiniteGrid>;
}
<template>
<packing-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</packing-infinite-grid>
</template>
<script lang="ts">
import { PackingInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
PackingInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<template>
<packing-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
</packing-infinite-grid>
</template>
<script lang="ts">
import { PackingInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
PackingInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];
},
},
};
</script>
<div NgxPackingInfiniteGrid
class="container"
[gap]="5"
[items]="items"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<div class="item" *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" />
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
</div>
import { Component, Input } from '@angular/core';
import { OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
groupBy(_: any, item: any) {
return item.groupKey;
}
trackBy(_: any, item: any) {
return item.key;
}
onRequestAppend(e: OnRequestAppend) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...this.getItems(nextGroupKey, 10),
];
}
}
<script>
import { PackingInfiniteGrid } from "@egjs/svelte-infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<PackingInfiniteGrid
class="container"
gap={5}
{items}
on:requestAppend={({ detail: e }) => {
const nextGroupKey = (+e.groupKey || 0) + 1;
items = [...items, ...getItems(nextGroupKey, 10)];
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{/each}
</PackingInfiniteGrid>
Insert Data
Through scrolling, when the scroll reaches the end, the requestAppend
event is raised, and when it reaches the start, the requestPrepend
event is raised. You can add data within this event.
- You can set the key of an item through
itemBy
prop. - You can set the group's key through
groupBy
prop.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
If the append
method or prepend
method is used, there is no need to use a separate key. You can set the groupKey through the second argument.
ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
});
- React's groupBy default is jsx's
data-grid-groupkey
prop. (attributePrefix: data-grid-) - React's itemBy default is jsx's key.
const [items, setItems] = React.useState([]);
<MasonryInfiniteGrid
groupBy={(jsx) => jsx.props["data-grid-groupkey"]}
itemBy={(jsx) => jsx.key}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}}>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>
- Vue's groupBy default is jsx's
data-grid-groupkey
prop. (attributePrefix: data-grid-) - Vue's itemBy default is jsx's key.
<masonry-infinite-grid
:itemBy="itemBy"
:groupBy="groupBy"
@request-append="onRequestAppend">
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
...
</div>
</masonry-infinite-grid>
export default {
data() {
return {
items: [],
},
},
methods: {
itemBy(jsx) {
const key = jsx.key;
return key == null ? i : key;
},
groupBy(jsx) {
const props = jsx.props || jsx.data?.attrs;
return props ? props[`data-grid-groupkey`] : undefined;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
},
};
- Vue's groupBy default is jsx's
data-grid-groupkey
prop. (attributePrefix: data-grid-) - Vue's itemBy default is jsx's key.
<masonry-infinite-grid
:itemBy="itemBy"
:groupBy="groupBy"
@request-append="onRequestAppend">
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
...
</div>
</masonry-infinite-grid>
export default {
data() {
return {
items: [],
},
},
methods: {
itemBy(jsx) {
const key = jsx.key;
return key == null ? i : key;
},
groupBy(jsx) {
const props = jsx.props || jsx.data?.attrs;
return props ? props[`${attributePrefix}groupkey`] : undefined;
},
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
},
};
<div NgxMasonryInfiniteGrid
class="container"
[items]="items"
[trackBy]="trackBy"
[groupBy]="groupBy"
[useLoading]="true"
(requestAppend)="onRequestAppend($event)"
#ig
>
<div class="item" *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
...
</div>
</div>
export default class App {
items = [];
groupBy(_: any, item: any) {
return item.groupKey;
}
trackBy(_: any, item: any) {
return item.key;
}
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}
};
- Svelte's
groupBy
default is item'sgroupKey
. - Svelte's
itemBy
default is items'skey
.
<script>
let items = [];
</script>
<MasonryInfiniteGrid
items={items}
groupBy={(item) => item.groupKey}
itemBy={(item) => item.key}
on:requestAppend={({ detail: e }) => {
items = [
...items,
...getItems(nextGroupKey, 10),
];
}}>
{#each visibleItems as item (item.key)}
<div class="item"></div>
{/each}
</MasonryInfiniteGrid>
Wait Data Loading
Use wait & ready
If you want to add items asynchronously, call the e.wait
function and when the data is ready call the e.ready
function.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 1000);
});
const [items, setItems] = React.useState([]);
<MasonryInfiniteGrid
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}, 1000);
}}>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>
export default {
data() {
return {
items: [],
},
},
methods: {
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
},
};
export default {
data() {
return {
items: [],
},
},
methods: {
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
},
};
export default class App {
items = [];
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
}
};
<script>
let items = [];
</script>
<MasonryInfiniteGrid
on:requestAppend={({ detail: e }) => {
e.wait();
setTimeout(() => {
e.ready();
items = [
...items,
...getItems(nextGroupKey, 10),
];
}, 1000);
}}>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>
Use Placeholder
You can add placeholders to show instead while data is being loaded/added. The placeholder is placed on the grid instead of the actual item and can be maintained until the actual item is added.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
You can set a placeholder through the ig.setPlaceholder
method.
ig.setPlaceholder({
html: `<div class="placeholder"></div>`,
});
ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 1000);
});
You can set the placeholder via the placeholder prop.
const [items, setItems] = React.useState([]);
<MasonryInfiniteGrid
placeholder={<div className="placeholder"></div>}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}, 1000);
}}>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>
A placeholder can be set via a placeholder slot.
<masonry-infinite-grid
@request-append="onRequestAppend">
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
<template v-slot:placeholder="{ item }">
<div
class="placeholder"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
</template>
</masonry-infinite-grid>
export default {
data() {
return {
items: [],
},
},
methods: {
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
},
};
A placeholder can be set via a placeholder slot.
<masonry-infinite-grid
@request-append="onRequestAppend">
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
<template v-slot:placeholder="{ item }">
<div
class="placeholder"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
</template>
</masonry-infinite-grid>
export default {
data() {
return {
items: [],
},
},
methods: {
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
},
};
You can set the placeholder via usePlaceholder(true).
<div NgxMasonryInfiniteGrid
class="container"
[usePlaceholder]="true"
(requestAppend)="onRequestAppend($event)"
#ig
>
<ng-container *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="item" *ngIf="item.type === ITEM_TYPE.NORMAL"></div>
<div class="placeholder" *ngIf="item.type === ITEM_TYPE.VIRTUAL"></div>
</ng-container>
</div>
import { ITEM_TYPE } from "@egjs/infinitegrid";
export default class App {
ITEM_TYPE = ITEM_TYPE;
items = [];
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
}
};
You can set the placeholder via usePlaceholder(true).
<script>
import { ITEM_TYPE } from "@egjs/infinitegrid";
let items = [];
</script>
<MasonryInfiniteGrid
usePlaceholder={true}
on:requestAppend={({ detail: e }) => {
e.wait();
setTimeout(() => {
e.ready();
items = [
...items,
...getItems(nextGroupKey, 10),
];
}, 1000);
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
{#if item.type === ITEM_TYPE.NORMAL}
<div class="item"></div>
{:else if item.type === ITEM_TYPE.VIRTUAL}
<div class="placeholder" />
{/if}
{/each}
</MasonryInfiniteGrid>
Use loading
You can show the loading bar while the data is loading. It can be added by calling the e.wait
function, and the loading bar automatically disappears when data is loaded.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
You can set a loading through the ig.setLoading
method.
ig.setLoading({
html: `<div class="loading">Loading...</div>`,
});
ig.on("requestAppend", e => {
const nextGroupKey = (+e.groupKey || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 1000);
});
You can set the loading via the loading prop.
const [items, setItems] = React.useState([]);
<MasonryInfiniteGrid
loading={<div className="loading">Loading...</div>}
onRequestAppend={(e) => {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
setItems([
...items,
...getItems(nextGroupKey, 10),
]);
}, 1000);
}}>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>
A loading can be set via a loading slot.
<masonry-infinite-grid
@request-append="onRequestAppend">
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
<template v-slot:loading="{ item }">
<div
class="loading"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>Loading...</div>
</template>
</masonry-infinite-grid>
export default {
data() {
return {
items: [],
},
},
methods: {
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
},
};
A loading can be set via a loading slot.
<masonry-infinite-grid
@request-append="onRequestAppend">
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
<template v-slot:loading="{ item }">
<div
class="loading"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>Loading...</div>
</template>
</masonry-infinite-grid>
export default {
data() {
return {
items: [],
},
},
methods: {
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
},
};
You can set the loading via useLoading(true).
<div NgxMasonryInfiniteGrid
class="container"
[useLoading]="true"
(requestAppend)="onRequestAppend($event)"
#ig
>
<ng-container *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="item" *ngIf="item.type === ITEM_TYPE.NORMAL"></div>
<div class="loading" *ngIf="item.type === ITEM_TYPE.LOADING">Loading...</div>
</ng-container>
</div>
import { ITEM_TYPE } from "@egjs/infinitegrid";
export default class App {
ITEM_TYPE = ITEM_TYPE;
items = [];
onRequestAppend(e) {
const nextGroupKey = (+e.groupKey! || 0) + 1;
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...getItems(nextGroupKey, 10),
];
}, 1000);
}
};
You can set the loading via useLoading(true).
<script>
import { ITEM_TYPE } from "@egjs/infinitegrid";
let items = [];
</script>
<MasonryInfiniteGrid
useLoading={true}
on:requestAppend={({ detail: e }) => {
e.wait();
setTimeout(() => {
e.ready();
items = [
...items,
...getItems(nextGroupKey, 10),
];
}, 1000);
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
{#if item.type === ITEM_TYPE.NORMAL}
<div class="item"></div>
{:else if item.type === ITEM_TYPE.LOADING}
<div class="loading">Loading...</div>
{/if}
{/each}
</MasonryInfiniteGrid>
Restore Status
You want to save the current status to storage before moving the page and restore it after returning the page.
If it does not support BF Cache like Safari, you need to save and restore the status.
InfiniteGrid provides a way to get and restore status.
If you want to restore dynamically, call the setStatus
method.
In the framework, items must also be saved and restored.
Get Status & Restore Status
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
Get Status
const status = ig.getStatus();
Restore Status
const ig = new MasonryInfiniteGrid(...);
ig.setStatus(status);
Get Status
const igRef = React.useRef();
igRef.current.getStatus();
<MasonryInfiniteGrid
ref={igRef}>...</MasonryInfiniteGrid>
Restore Status
<MasonryInfiniteGrid
ref={igRef}
status={status}
>...</MasonryInfiniteGrid>
Get Status
<masonry-infinite-grid ref="ig">
...
</masonry-infinite-grid>
this.$refs.ig.getStatus();
Restore Status
<masonry-infinite-grid v-bind:status="status">
...
</masonry-infinite-grid>
Get Status
<masonry-infinite-grid ref="ig">
...
</masonry-infinite-grid>
this.$refs.ig.getStatus();
Restore Status
<masonry-infinite-grid v-bind:status="status">
...
</masonry-infinite-grid>
Get Status
<div NgxMasonryInfiniteGrid #ig>
...
</div>
import { Component, Input, AfterViewInit } from '@angular/core';
import { NgxInfiniteGridComponent } from '@egjs/ngx-infinitegrid';
class App {
@ViewChild("ig") ig!: NgxInfiniteGridComponent;
getStatus() {
this.ig.getStatus();
}
}
Restore Status
<div NgxMasonryInfiniteGrid [status]="status" #ig>
...
</div>
Get Status
let ig;
ig.getStatus();
<MasonryInfiniteGrid
bind:this={ig}>
</MasonryInfiniteGrid>
Restore Status
<MasonryInfiniteGrid
status={status}
bind:this={ig}>
</MasonryInfiniteGrid>
Restore Visible Status
To reduce the size of the status, only the status of the items in the visible area is fetched.
import { STATUS_TYPE } from "@egjs/infinitegrid";
// (default) gets all infos
ig.getStatus(STATUS_TYPE.NOT_REMOVE);
// gets visible infos
ig.getStatus(STATUS_TYPE.REMOVE_INVISIBLE_GROUPS);
// gets visible infos. However, the information is simplified for invisible items.
ig.getStatus(STATUS.MINIMIZE_INVISIBLE_ITEMS);
// gets visible infos. However, invisible items are removed and only the outline remains.
ig.getStatus(STATUS.MINIMIZE_INVISIBLE_GROUPS);
import { STATUS_TYPE } from "@egjs/infinitegrid";
const status = ig.getStatus(STATUS_TYPE.MINIMIZE_INVISIBLE_ITEMS);
const [startCursor, endCursor] = status.groupManager.itemCursors;
const itemsStatus = items.slice(startCursor, endCursor + 1);
Restore Visible Status with virtual items
Since you got the status for the visible area, replace it with a placeholder to handle the invisible area.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { MasonryInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push(`<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`);
}
return nextItems;
}
const ig = new MasonryInfiniteGrid(".container", {
gap: 5,
});
ig.setPlaceholder({
html: `<div class="placeholder"></div>`,
});
ig.on("requestPrepend", e => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
ig.prepend(getItems(nextGroupKey, 10), nextGroupKey);
}, 200);
}
});
ig.on("requestAppend", e => {
if (e.isVirtual) {
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
ig.append(getItems(nextGroupKey, 10), nextGroupKey);
}, 200);
}
});
ig.renderItems();
import * as React from "react";
import { MasonryInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <MasonryInfiniteGrid
className="container"
gap={5}
placeholder={<div className="placeholder"></div>}
onRequestPrepend={(e) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
setItems([
...getItems(e.nextGroupKey, 10),
...items,
]);
}, 200);
}
}}
onRequestAppend={(e) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
setItems([
...items,
...getItems(e.nextGroupKey, 10),
]);
}, 200);
}
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>;
}
<template>
<masonry-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
v-on:request-prepend="onRequestPrepend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
<template v-slot:placeholder="{ item }">
<div
class="placeholder"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
</template>
</masonry-infinite-grid>
</template>
<script lang="ts">
import { MasonryInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
MasonryInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestPrepend(e: OnRequestPrepend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.getItems(e.nextGroupKey, 10),
...this.items,
];
}, 200);
}
},
onRequestAppend(e: OnRequestAppend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...this.getItems(e.nextGroupKey, 10),
];
}, 200);
}
},
};
</script>
<template>
<masonry-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
v-on:request-prepend="onRequestPrepend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
<template v-slot:placeholder="{ item }">
<div
class="placeholder"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
</template>
</masonry-infinite-grid>
</template>
<script lang="ts">
import { MasonryInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
MasonryInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestPrepend(e: OnRequestPrepend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.getItems(e.nextGroupKey, 10),
...this.items,
];
}, 200);
}
},
onRequestAppend(e: OnRequestAppend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...this.getItems(e.nextGroupKey, 10),
];
}, 200);
}
},
};
</script>
<div NgxMasonryInfiniteGrid
class="container"
[gap]="5"
[items]="items"
[usePlaceholder]="true"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
(requestPrepend)="onRequestPrepend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<ng-container *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="item" *ngIf="item.type === ITEM_TYPE.NORMAL">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" />
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
<div class="placeholder" *ngIf="item.type === ITEM_TYPE.VIRTUAL"></div>
</ng-contianer>
</div>
import { Component, Input } from '@angular/core';
import { ITEM_TYPE, OnRequestPrepend, OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
ITEM_TYPE = ITEM_TYPE;
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
onRequestPrepend(e: OnRequestPrepend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.getItems(e.nextGroupKey, 10),
...this.items,
];
}, 200);
}
}
onRequestAppend(e: OnRequestAppend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...this.getItems(e.nextGroupKey, 10),
];
}, 200);
}
}
}
<script>
import { MasonryInfiniteGrid } from "@egjs/svelte-infinitegrid";
import { ITEM_TYPE } from "@egjs/infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<MasonryInfiniteGrid
class="container"
gap={5}
{items}
usePlaceholder={true}
on:requestPrepend={({ detail: e }) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
items = [
...getItems(e.nextGroupKey, 10),
...items,
];
}, 200);
}
}}
on:requestAppend={({ detail: e }) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
items =[
...items,
...getItems(e.nextGroupKey, 10),
];
}, 200);
}
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
{#if item.type === ITEM_TYPE.NORMAL}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{:else if item.type === ITEM_TYPE.VIRTUAL}
<div class="placeholder" />
{/if}
{/each}
</MasonryInfiniteGrid>
Restore Visible Status with virtual items and scroll 0
Since you got the status for the visible area, replace it with a placeholder to handle the invisible area.
Even if you move the scroll to 0 to the invisible area, all items can be restored.
- JavaScript
- React
- Vue@2
- Vue@3
- Angular
- Svelte
<div class="container"></div>
import { MasonryInfiniteGrid } from "@egjs/infinitegrid";
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const num = nextGroupKey * count + i;
nextItems.push({
groupKey: nextGroupKey,
key: num,
html: `<div class="item">
<div class="thumbnail">
<img src="https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg" alt="egjs" />
</div>
<div class="info">egjs ${num}</div>
</div>`,
});
}
return nextItems;
}
const ig = new MasonryInfiniteGrid(".container", {
gap: 5,
});
ig.setPlaceholder({
html: `<div class="placeholder"></div>`,
});
ig.on("requestPrepend", e => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
ig.prepend(e.nextGroupKeys.map(key => getItems(key, 10)).flat());
}, 200);
}
});
ig.on("requestAppend", e => {
if (e.isVirtual) {
e.wait();
e.currentTarget.appendPlaceholders(5, nextGroupKey);
setTimeout(() => {
e.ready();
ig.append(e.nextGroupKeys.map(key => getItems(key, 10)).flat());
}, 200);
}
});
ig.renderItems();
import * as React from "react";
import { MasonryInfiniteGrid } from "@egjs/react-infinitegrid";
function getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
const Item = ({ num }: any) => <div className="item" style={{
width: "250px",
}}>
<div className="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${(num % 33) + 1}.jpg`}
alt="egjs"
/>
</div>
<div className="info">{`egjs ${num}`}</div>
</div>;
export default function App() {
const [items, setItems] = React.useState(() => getItems(0, 10));
return <MasonryInfiniteGrid
className="container"
gap={5}
placeholder={<div className="placeholder"></div>}
onRequestPrepend={(e) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
setItems([
...e.nextGroupKeys.map(key => getItems(key as number, 10)).flat(),
...items,
]);
}, 200);
}
}}
onRequestAppend={(e) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
setItems([
...items,
...e.nextGroupKeys.map(key => getItems(key as number, 10)).flat(),
]);
}, 200);
}
}}
>
{items.map((item) => <Item data-grid-groupkey={item.groupKey} key={item.key} num={item.key} />)}
</MasonryInfiniteGrid>;
}
<template>
<masonry-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
v-on:request-prepend="onRequestPrepend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
<template v-slot:placeholder="{ item }">
<div
class="placeholder"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
</template>
</masonry-infinite-grid>
</template>
<script lang="ts">
import { MasonryInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
components: {
MasonryInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestPrepend(e: OnRequestPrepend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...e.nextGroupKeys.map(key => this.getItems(key, 10)).flat(),
...this.items,
];
}, 200);
}
},
onRequestAppend(e: OnRequestAppend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...e.nextGroupKeys.map(key => this.getItems(key, 10)).flat(),
];
}, 200);
}
},
};
</script>
<template>
<masonry-infinite-grid
class="container"
v-bind:gap="5"
v-on:request-append="onRequestAppend"
v-on:request-prepend="onRequestPrepend"
>
<div
class="item"
v-for="item in items"
:key="item.key"
:data-grid-groupkey="item.groupKey"
>
<div class="thumbnail">
<img
v-bind:src="
'https://naver.github.io/egjs-infinitegrid/assets/image/' +
((item.key % 33) + 1) +
'.jpg'
"
alt="egjs"
/>
</div>
<div class="info">egjs {{ item.key }}</div>
</div>
<template v-slot:placeholder="{ item }">
<div
class="placeholder"
:key="item.key"
:data-grid-groupkey="item.groupKey"
></div>
</template>
</masonry-infinite-grid>
</template>
<script lang="ts">
import { MasonryInfiniteGrid } from "@egjs/vue3-infinitegrid";
export default {
components: {
MasonryInfiniteGrid,
},
data() {
return {
items: this.getItems(0, 10),
};
},
methods: {
getItems(nextGroupKey: number, count: number) {
const nextItems: any[] = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
},
onRequestPrepend(e: OnRequestPrepend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...e.nextGroupKeys.map(key => this.getItems(key, 10)).flat(),
...this.items,
];
}, 200);
}
},
onRequestAppend(e: OnRequestAppend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...e.nextGroupKeys.map(key => this.getItems(key, 10)).flat(),
];
}, 200);
}
},
};
</script>
<div NgxMasonryInfiniteGrid
class="container"
[gap]="5"
[items]="items"
[usePlaceholder]="true"
[trackBy]="trackBy"
[groupBy]="groupBy"
(requestAppend)="onRequestAppend($event)"
(requestPrepend)="onRequestPrepend($event)"
*ngFor="let item of [0]; trackBy: randomTrackBy;"
#ig
>
<ng-container *ngFor ="let item of ig.visibleItems; trackBy: trackBy;">
<div class="item" *ngIf="item.type === ITEM_TYPE.NORMAL">
<div class="thumbnail">
<img [src]="'https://naver.github.io/egjs-infinitegrid/assets/image/' + (item.data.key % 33 + 1) + '.jpg'" alt="egjs" />
</div>
<div class="info">egjs {{item.data.key}}</div>
</div>
<div class="placeholder" *ngIf="item.type === ITEM_TYPE.VIRTUAL"></div>
</ng-contianer>
</div>
import { Component, Input } from '@angular/core';
import { ITEM_TYPE, OnRequestPrepend, OnRequestAppend } from '@egjs/infinitegrid';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
ITEM_TYPE = ITEM_TYPE;
items = this.getItems(0, 10);
getItems(nextGroupKey: number, count: number) {
const nextItems = [];
const nextKey = nextGroupKey * count;
for (let i = 0; i < count; ++i) {
nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
}
return nextItems;
}
onRequestPrepend(e: OnRequestPrepend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...e.nextGroupKeys.map(key => this.getItems(key as number, 10)).flat(),
...this.items,
];
}, 200);
}
}
onRequestAppend(e: OnRequestAppend) {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
this.items = [
...this.items,
...e.nextGroupKeys.map(key => this.getItems(key as number, 10)).flat(),
];
}, 200);
}
}
}
<script>
import { MasonryInfiniteGrid } from "@egjs/svelte-infinitegrid";
import { ITEM_TYPE } from "@egjs/infinitegrid";
let items = getItems(0, 10);
function getItems(nextGroupKey, count) {
const nextItems = [];
for (let i = 0; i < count; ++i) {
const nextKey = nextGroupKey * count + i;
nextItems.push({ groupKey: nextGroupKey, key: nextKey });
}
return nextItems;
}
</script>
<MasonryInfiniteGrid
class="container"
gap={5}
{items}
usePlaceholder={true}
on:requestPrepend={({ detail: e }) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
items = [
...e.nextGroupKeys.map(key => getItems(key, 10)).flat(),
...items,
];
}, 200);
}
}}
on:requestAppend={({ detail: e }) => {
if (e.isVirtual) {
e.wait();
setTimeout(() => {
e.ready();
items =[
...items,
...e.nextGroupKeys.map(key => getItems(key, 10)).flat(),
];
}, 200);
}
}}
let:visibleItems
>
{#each visibleItems as item (item.key)}
{#if item.type === ITEM_TYPE.NORMAL}
<div class="item">
<div class="thumbnail">
<img
src={`https://naver.github.io/egjs-infinitegrid/assets/image/${
(item.key % 33) + 1
}.jpg`}
alt="egjs"
/>
</div>
<div class="info">{`egjs ${item.key}`}</div>
</div>
{:else if item.type === ITEM_TYPE.VIRTUAL}
<div class="placeholder" />
{/if}
{/each}
</MasonryInfiniteGrid>
Use Transition
If you want to use transition, use CSS.
.item {
transition: all ease 0.2s;
}