aslan-h5/src/components/itemCenter.vue
2026-03-27 20:24:13 +08:00

175 lines
3.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- src/components/itemCenter.vue -->
<template>
<div style="position: relative; width: 100%" ref="containerRef">
<!-- 背景图 -->
<img
v-if="shouldShowImage"
v-smart-img
:src="imgUrl"
:class="flip ? 'flipImg' : ''"
alt=""
style="width: 100%; height: 100%; display: block"
/>
<div
v-else
class="placeholder"
:style="{
width: '100%',
height: '100%',
backgroundColor: 'transparent',
}"
></div>
<!-- 内容 -->
<div
class="scrollY"
style="
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
"
:style="contentStyle"
>
<slot></slot>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, computed, onUnmounted, watch } from 'vue'
const props = defineProps({
imgUrl: {
type: String,
default: '',
required: true,
},
contentStyle: {
type: String,
default: '',
},
// 懒加载预加载范围
rootMargin: {
type: String,
default: '100px',
},
// 是否翻转图片
flip: {
type: Boolean,
default: false,
},
// 是否启用懒加载
lazy: {
type: Boolean,
default: false,
},
// 是否立即显示优先级高于lazy
immediate: {
type: Boolean,
default: false,
},
// 新增:父容器显示状态
show: {
type: Boolean,
default: true,
},
})
const containerRef = ref(null)
const isVisible = ref(false)
let observer = null
// 是否应该显示图片
const shouldShowImage = computed(() => {
// 如果标记为立即显示或禁用懒加载,则直接显示
if (props.immediate || !props.lazy) {
return true
}
// 否则根据是否可见决定
return isVisible.value
})
// 判断是否为OSS图片
const isOSSImage = computed(() => {
return (
props.imgUrl.startsWith('/oss/h5/') ||
props.imgUrl.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5')
)
})
// 创建交叉观察器
const createObserver = () => {
if (!props.lazy || props.immediate) return
if (!containerRef.value) return
// 清理旧观察者
if (observer) {
observer.disconnect()
}
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
isVisible.value = true
observer.unobserve(entry.target)
}
})
},
{
rootMargin: props.rootMargin, // 提前100px开始加载
threshold: 0,
},
)
observer.observe(containerRef.value)
}
onMounted(() => {
createObserver()
})
// 监听 show 属性变化,重新创建观察者
watch(
() => props.show,
(newVal) => {
if (newVal && props.lazy && !props.immediate) {
// 延迟执行,确保 DOM 已渲染
setTimeout(() => {
createObserver()
}, 100)
}
},
)
onUnmounted(() => {
if (observer) {
observer.disconnect()
}
})
</script>
<style lang="scss" scoped>
.placeholder {
transition: opacity 0.3s ease;
}
.scrollY::-webkit-scrollbar {
display: none;
}
[dir='rtl'] .flipImg {
transform: scaleX(-1);
}
</style>