Infinite scroll
Carga incremental al hacer scroll cerca del final — patrón ion-infinite-scroll. Usa IntersectionObserver sobre un sentinel y dispara iscroll:more con dos callbacks (done, end).
Cuándo usar: listas medianas (cientos a pocos miles de items) donde se quiere paginación natural. Para 10 000+ filas usa
virtual-scroll en su lugar (solo renderiza lo visible).
Copy
<div data-signals-rows="20" data-signals-end="false" style="max-height:340px; overflow:auto; background:var(--bg-1); border:var(--border-w) solid var(--line); border-radius:var(--radius-md); padding:.5rem 1rem">
<ul id="rows-list-1" class="list" style="margin:0" data-text="
Array.from({length:$rows}, (_,i) => `<li style='padding:.5rem 0;border-bottom:var(--border-w) solid var(--line)'>Item #${(i+1).toString().padStart(4,'0')} — payload de ejemplo</li>`).join('')
"></ul>
<div data-on:iscroll:more="
if ($rows >= 80) { evt.detail.end(); }
else { setTimeout(() => { $rows = $rows + 20; evt.detail.done(); }, 600); }
">
<div class="iscroll" data-iscroll-margin="300px 0px">
<div class="iscroll-sentinel" aria-hidden="true"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
</div>
</div>
Copy
{% from "infinite-scroll.jinja" import infinite_scroll %}
<div data-signals-rows="20" data-signals-end="false" style="max-height:340px; overflow:auto">
<ul id="rows-list" class="list" data-text="
Array.from({length:$rows}, (_,i) => `<li>Item ${i+1}</li>`).join('')
"></ul>
<div data-on:iscroll:more="
if ($rows >= 80) { $end = true; evt.detail.end(); }
else { setTimeout(() => { $rows = $rows + 20; evt.detail.done(); }, 600); }
">
{{ infinite_scroll(scroll_root="[data-signals-rows]") }}
</div>
</div>
Copy
{% from "infinite-scroll.jinja" import infinite_scroll %}
<div data-signals-rows="20" data-signals-end="false" style="max-height:340px; overflow:auto">
<ul id="rows-list" class="list" data-text="
Array.from({length:$rows}, (_,i) => `<li>Item ${i+1}</li>`).join('')
"></ul>
<div data-on:iscroll:more="
if ($rows >= 80) { $end = true; evt.detail.end(); }
else { setTimeout(() => { $rows = $rows + 20; evt.detail.done(); }, 600); }
">
{{ infinite_scroll(scroll_root="[data-signals-rows]") }}
</div>
</div>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />
Copy
<div class="iscroll is-loading">
<div class="iscroll-sentinel"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
Copy
<div class="iscroll is-loading">
<div class="iscroll-sentinel"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
Copy
<div class="iscroll is-loading">
<div class="iscroll-sentinel"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />
Copy
<div class="iscroll is-end">
<div class="iscroll-sentinel"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
Copy
<div class="iscroll is-end">
<div class="iscroll-sentinel"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
Copy
<div class="iscroll is-end">
<div class="iscroll-sentinel"></div>
<div class="iscroll-loader">Cargando más…</div>
<div class="iscroll-end">Fin de la lista</div>
</div>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />
API · macro infinite_scroll()
Prop Tipo Default Descripción
loading_labelstr "Cargando más…"Texto del loader.
end_labelstr "Fin de la lista"Texto al alcanzar el final.
marginstr (CSS) "300px 0px"rootMargin del IntersectionObserver. Más grande = pre-carga antes.
scroll_rootstr (selector) NoneSelector del scroller. Sin esto usa el viewport.
Evento
Evento Detail Descripción
iscroll:more{done(): void, end(): void}El sentinel entró en viewport. Llama done() al cargar; end() si no hay más (desconecta el observer y muestra .iscroll-end).
API JS · window.OKInfiniteScroll
OKInfiniteScroll.init(el)
OKInfiniteScroll.initAll(root)