Merge branch 'preview-fixes' of https://github.com/the1812/Bilibili-Evolved into preview-fixes

This commit is contained in:
the1812 2023-11-07 23:15:41 +08:00
commit 50ae796dff
2 changed files with 74 additions and 2 deletions

View File

@ -4,7 +4,7 @@
<VideoCard v-for="c of cards" :key="c.id" :data="c" />
</div>
<VEmpty v-if="!loading && cards.length === 0" />
<ScrollTrigger v-if="!error" @trigger="loadCards" />
<ScrollTrigger v-if="!error" ref="scrollTrigger" detect-viewport @trigger="loadCards" />
<MinimalHomeOperations v-if="cards.length > 0" @refresh="refresh" />
</div>
</template>
@ -43,6 +43,7 @@ export default Vue.extend({
try {
this.error = false
this.loading = true
this.$refs.scrollTrigger.setLoadState('loading')
this.cards = lodash.uniqBy(
[...this.cards, ...(await getVideoFeeds('video', this.lastID))],
it => it.id,
@ -50,12 +51,17 @@ export default Vue.extend({
} catch (error) {
logError(error)
this.error = true
this.$refs.scrollTrigger.setLoadState('error')
} finally {
this.loading = false
if (this.loaded) {
this.$refs.scrollTrigger.setLoadState('loaded')
}
}
},
async refresh() {
this.cards = []
this.$refs.scrollTrigger.resetIsFirstLoad()
},
},
})

View File

@ -7,23 +7,89 @@
</template>
<script lang="ts">
import { useScopedConsole } from '@/core/utils/log'
import { delay } from '@/core/utils/'
export default Vue.extend({
components: {
VLoading: () => import('./VLoading.vue').then(m => m.default),
},
props: {
detectViewport: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
isFirstLoad: true,
isViewportTriggerRunning: false,
parentLoadState: 'none',
}
},
async mounted() {
const console = useScopedConsole('ScrollTrigger')
const element = this.$el as HTMLElement
const { visible } = await import('@/core/observer')
visible(element, records => {
visible(element, async records => {
if (records.some(r => r.intersectionRatio > 0)) {
console.log('Intersection Observer trigger')
this.trigger()
if (!this.detectViewport && !this.isFirstLoad && this.isViewportTriggerRunning) {
return
}
this.isViewportTriggerRunning = true
while (this.getVisibleStateByViewport(element)) {
await delay(500)
// setLoadState continue
//
if (this.parentLoadState !== 'loaded') {
continue
}
//
if (!this.getVisibleStateByViewport(element)) {
break
}
console.log('is first load & viewport trigger')
this.trigger()
}
this.isFirstLoad = false
}
})
},
methods: {
/**
* 当元素顶部位于视口内部时返回为正数位于视口外部时返回为负数正好位于视口底部时返回为零
* @param element HTML 元素
* @returns 元素顶部到视口底部的距离
*/
getElementToViewportBottomDistance(element: HTMLElement): number {
return document.documentElement.clientHeight - element.getBoundingClientRect().top
},
/**
* 当元素顶部在视口内部时返回 true
* 为避免极端情况当元素顶部到视口底部的距离大于 -20 时同样返回 true
* @param element HTML 元素
* @returns 元素可视情况
*/
getVisibleStateByViewport(element: HTMLElement): boolean {
return Boolean(this.getElementToViewportBottomDistance(element) > -20)
},
setLoadState(loadState: 'loading' | 'error' | 'loaded') {
this.parentLoadState = loadState
},
resetIsFirstLoad() {
this.isFirstLoad = true
},
trigger() {
this.$emit('trigger')
},