mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge branch 'preview-fixes' of https://github.com/the1812/Bilibili-Evolved into preview-fixes
This commit is contained in:
commit
50ae796dff
@ -4,7 +4,7 @@
|
|||||||
<VideoCard v-for="c of cards" :key="c.id" :data="c" />
|
<VideoCard v-for="c of cards" :key="c.id" :data="c" />
|
||||||
</div>
|
</div>
|
||||||
<VEmpty v-if="!loading && cards.length === 0" />
|
<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" />
|
<MinimalHomeOperations v-if="cards.length > 0" @refresh="refresh" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -43,6 +43,7 @@ export default Vue.extend({
|
|||||||
try {
|
try {
|
||||||
this.error = false
|
this.error = false
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
this.$refs.scrollTrigger.setLoadState('loading')
|
||||||
this.cards = lodash.uniqBy(
|
this.cards = lodash.uniqBy(
|
||||||
[...this.cards, ...(await getVideoFeeds('video', this.lastID))],
|
[...this.cards, ...(await getVideoFeeds('video', this.lastID))],
|
||||||
it => it.id,
|
it => it.id,
|
||||||
@ -50,12 +51,17 @@ export default Vue.extend({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error)
|
logError(error)
|
||||||
this.error = true
|
this.error = true
|
||||||
|
this.$refs.scrollTrigger.setLoadState('error')
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
if (this.loaded) {
|
||||||
|
this.$refs.scrollTrigger.setLoadState('loaded')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async refresh() {
|
async refresh() {
|
||||||
this.cards = []
|
this.cards = []
|
||||||
|
this.$refs.scrollTrigger.resetIsFirstLoad()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,23 +7,89 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { useScopedConsole } from '@/core/utils/log'
|
import { useScopedConsole } from '@/core/utils/log'
|
||||||
|
import { delay } from '@/core/utils/'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
VLoading: () => import('./VLoading.vue').then(m => m.default),
|
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() {
|
async mounted() {
|
||||||
const console = useScopedConsole('ScrollTrigger')
|
const console = useScopedConsole('ScrollTrigger')
|
||||||
const element = this.$el as HTMLElement
|
const element = this.$el as HTMLElement
|
||||||
const { visible } = await import('@/core/observer')
|
const { visible } = await import('@/core/observer')
|
||||||
visible(element, records => {
|
visible(element, async records => {
|
||||||
if (records.some(r => r.intersectionRatio > 0)) {
|
if (records.some(r => r.intersectionRatio > 0)) {
|
||||||
console.log('Intersection Observer trigger')
|
console.log('Intersection Observer trigger')
|
||||||
this.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: {
|
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() {
|
trigger() {
|
||||||
this.$emit('trigger')
|
this.$emit('trigger')
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user