update
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { abonnieren } from './live'
|
||||
import MovieCard from './components/MovieCard.vue'
|
||||
import FilterSidebar from './components/FilterSidebar.vue'
|
||||
@@ -512,6 +512,56 @@ const visibleCanon = computed(() =>
|
||||
filterGruppen(canonGroups.value, search.value.trim().toLowerCase())
|
||||
)
|
||||
|
||||
// Gefiltert wird über den ganzen Katalog, gerendert nur der Anfang davon.
|
||||
// Alle 2554 Karten auf einmal sind in der Detailansicht über zehntausend
|
||||
// Bilder — der Browser meldet dann "Seite reagiert nicht".
|
||||
const STAPEL = 100
|
||||
const gezeigt = ref(STAPEL)
|
||||
|
||||
const aktuelleListe = computed(() =>
|
||||
activeTab.value === 'netflix' ? visible.value : visibleCanon.value
|
||||
)
|
||||
|
||||
const sichtbar = computed(() => aktuelleListe.value.slice(0, gezeigt.value))
|
||||
|
||||
// Jede neue Suche, jeder Filter und jeder Reiterwechsel fängt oben an
|
||||
watch([aktuelleListe, ansicht], () => {
|
||||
gezeigt.value = STAPEL
|
||||
})
|
||||
|
||||
async function mehrLaden() {
|
||||
if (gezeigt.value >= aktuelleListe.value.length) return
|
||||
gezeigt.value += STAPEL
|
||||
// Der Beobachter meldet sich nur beim Wechsel sichtbar/unsichtbar. Bleibt
|
||||
// der Fuß nach dem Nachladen im Blick — großer Bildschirm, kurze Liste —,
|
||||
// käme sonst nie ein zweiter Stapel.
|
||||
await nextTick()
|
||||
const el = nachschub.value
|
||||
if (el && el.getBoundingClientRect().top < window.innerHeight + 600) mehrLaden()
|
||||
}
|
||||
|
||||
// Der Fuß der Liste meldet sich, sobald er in Sichtweite kommt. Ein
|
||||
// Scroll-Handler müsste bei jedem Pixel rechnen, das hier nicht.
|
||||
// Gleich hier angelegt, nicht in onMounted: die Vorlage setzt die Referenz
|
||||
// schon beim ersten Zeichnen, da muss der Beobachter bereits stehen.
|
||||
const nachschub = ref(null)
|
||||
const beobachter = new IntersectionObserver(
|
||||
(eintraege) => {
|
||||
if (eintraege.some((e) => e.isIntersecting)) mehrLaden()
|
||||
},
|
||||
// Vorlauf, damit der Nachschub schon da ist, bevor die Liste endet
|
||||
{ rootMargin: '600px' }
|
||||
)
|
||||
|
||||
onUnmounted(() => beobachter.disconnect())
|
||||
|
||||
// Der Fuß verschwindet und kommt wieder, je nach Filter — also bei jedem
|
||||
// Wechsel neu anmelden
|
||||
watch(nachschub, (el, vorher) => {
|
||||
if (vorher) beobachter.unobserve(vorher)
|
||||
if (el) beobachter.observe(el)
|
||||
})
|
||||
|
||||
// Die Reihe zum geöffneten Film. Im Kanon ist das die Gruppe der Vorlage,
|
||||
// sonst TMDBs Collection — dort aber nur, was auch auf Netflix liegt.
|
||||
const series = computed(() => {
|
||||
@@ -681,10 +731,7 @@ onUnmounted(() => {
|
||||
</p>
|
||||
|
||||
<div class="grid" :class="ansicht">
|
||||
<template
|
||||
v-for="entry in activeTab === 'netflix' ? visible : visibleCanon"
|
||||
:key="entry.group"
|
||||
>
|
||||
<template v-for="entry in sichtbar" :key="entry.group">
|
||||
<MovieCard
|
||||
v-if="entry.parts.length === 1"
|
||||
:movie="entry.parts[0]"
|
||||
@@ -702,6 +749,10 @@ onUnmounted(() => {
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="gezeigt < aktuelleListe.length" ref="nachschub" class="nachschub">
|
||||
Lädt weitere Filme …
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FilterSidebar
|
||||
@@ -870,6 +921,13 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.nachschub {
|
||||
padding: 2rem 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.9rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
|
||||
|
||||
Reference in New Issue
Block a user