95 lines
2.5 KiB
Vue
95 lines
2.5 KiB
Vue
<!-- 只适合用于渲染过程较为复杂的组件,不然可能得不偿失
|
||
这么泛用的组件,性能差点也能理解 -->
|
||
<template>
|
||
<div class="miao-lazy" ref="miaoLazyRoot" :style="!show ? { minHeight, minWidth } : {}">
|
||
<slot v-if="show" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||
|
||
const props = defineProps({
|
||
disableLazy: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
// 仅在内容未加载时生效,用于占位
|
||
minHeight: {
|
||
type: String,
|
||
default: 'none',
|
||
},
|
||
minWidth: {
|
||
type: String,
|
||
default: 'none',
|
||
}
|
||
})
|
||
|
||
const miaoLazyRoot = ref<HTMLDivElement>()
|
||
|
||
const show = ref<boolean>(props.disableLazy)
|
||
|
||
const isVisible = (dom: HTMLDivElement) => {
|
||
const offset = dom.getBoundingClientRect().top
|
||
return offset > 0 && offset < 2000
|
||
}
|
||
|
||
const { showSlot, hideSlot, clearTimer } = (() => {
|
||
let timer: any
|
||
let timerInterval: any
|
||
const clearTimer = () => {
|
||
timer && clearTimeout(timer)
|
||
timerInterval && clearInterval(timerInterval)
|
||
timer = undefined
|
||
timerInterval = undefined
|
||
}
|
||
const hideSlot = () => {
|
||
clearTimer()
|
||
show.value = false
|
||
}
|
||
const showSlot = () => {
|
||
if (show.value === true) {
|
||
return
|
||
}
|
||
clearTimer()
|
||
// timer = setTimeout(() => {
|
||
if (!miaoLazyRoot.value || isVisible(miaoLazyRoot.value) === false) {
|
||
return
|
||
}
|
||
show.value = true
|
||
timerInterval = setInterval(() => {
|
||
if (show.value === false || miaoLazyRoot.value === undefined) {
|
||
return
|
||
}
|
||
if (isVisible(miaoLazyRoot.value) === false) {
|
||
hideSlot()
|
||
}
|
||
}, 1000)
|
||
// })
|
||
}
|
||
return { showSlot, hideSlot, clearTimer }
|
||
})()
|
||
|
||
onMounted(() => {
|
||
if (show.value === false) {
|
||
let options = {
|
||
threshold: 0
|
||
};
|
||
|
||
let observer: IntersectionObserver | undefined = new IntersectionObserver((entries) => {
|
||
if (entries[0].isIntersecting) {
|
||
showSlot()
|
||
// miaoLazyRoot.value && observer?.unobserve(miaoLazyRoot.value)
|
||
// observer = undefined
|
||
} else {
|
||
hideSlot()
|
||
}
|
||
}, options);
|
||
miaoLazyRoot.value && observer.observe(miaoLazyRoot.value);
|
||
}
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
clearTimer()
|
||
})
|
||
</script> |