案例
話不多說直接代碼見
父組件模版
<template>
<div
class="scroll-list"
:style="`height:${viewH}px;overflow-y: auto;`"
@scroll="scrollHandler"
>
<div class="card-content" :style="`height:${scrollH}px;`">
<div class="card_box" :style="`transform:translateY(${offsetY}px)`">
<Card
v-for="(item, index) in showList"
:key="index"
:itemSource="item"
:index="index"
></Card>
</div>
</div>
</div>
</template>
父組件上的邏輯代碼
<script setup>
import Card from "@/components/scrollList/card.vue"; // 引入子組件
import { pageQueryCompetitor } from "@/api/index.js"; // 后端接口引入
import { onMounted, ref } from "vue";
const sourceList = ref([]); // 所有數(shù)據(jù)
const showList = ref([]); // 頁(yè)面實(shí)際展示
const viewH = ref(500); // 外層容器高度
const itemH = ref(70); // 單個(gè)高度
const scrollH = ref(0); // 滾動(dòng)容器高度
const showNum = ref(0); // 展示幾個(gè)
const lastTime = ref(0);
const offsetY = ref(0); // 滾動(dòng)偏移量
const current = ref(1);
const isLoading = ref(false); // 是否接口還在加載中
const isFail = ref(false); // 請(qǐng)求是否失敗
const isEnd = ref(false); // 數(shù)據(jù)是否加載完了
const scrollHandler = async (e) => {
let newTime = new Date().getTime();
let bottomH = itemH.value * showNum.value * 2;
if (newTime - lastTime.value > 10) {
let scrollTop = e.target.scrollTop;
// 以1屏為基準(zhǔn)進(jìn)行偏移
offsetY.value = scrollTop - (scrollTop % (itemH.value * showNum.value));
// 觸底判斷
let bool = e.target.scrollHeight - viewH.value - scrollTop > bottomH;
if (!bool) {
getSliceHandler(scrollTop);
if (isLoading.value) return;
if (!isFail.value && !isEnd.value) {
current.value++;
}
isLoading.value = true;
await getHttpHandler();
} else {
getSliceHandler(scrollTop);
}
}
};
// 展示內(nèi)容進(jìn)行截取
const getSliceHandler = (scrollTop) => {
let index = Math.floor(scrollTop / (itemH.value * showNum.value));
showList.value = sourceList.value.slice(
index * showNum.value,
index * showNum.value + showNum.value * 2
);
};
// 獲取數(shù)據(jù)
const getHttpHandler = async () => {
// 傳給后端的入?yún)? let params = {
current: current.value,
eid: "4c8bd41b-2534-43c0-8643-5bf4dca1991e",
pageSize: 30,
queryType: 0,
sortType: 0,
};
try {
const { success, data } = await pageQueryCompetitor(params);
if (success) {
isFail.value = false;
if (!data.records.length) {
isEnd.value = true;
return;
}
sourceList.value.push(...data.records);
scrollH.value = sourceList.value.length * itemH.value;
lastTime.value = new Date().getTime();
isLoading.value = false;
}
} catch (e) {
isFail.value = true;
isLoading.value = false;
}
};
onMounted(async () => {
showNum.value = Math.floor(viewH.value / itemH.value) + 1;
await getHttpHandler();
showList.value = sourceList.value.slice(0, showNum.value * 2);
});
</script>
子組件模版
<template>
<div class="card">
<div class="item">{{ itemSource.competitor_name }}{{ index + 1 }}</div>
</div>
</template>
<script setup>
defineProps({
itemSource: {
type: Object,
default: {},
},
index: {
type: Number,
default: 0,
},
});
</script>
<style lang="scss" scoped>
.card {
padding-bottom: 10px;
.item {
width: 400px;
height: 60px;
background-color: #008c8c;
font-size: 14px;
}
}
</style>