背景:VUE 页面,点击按钮,弹框,内容从接口获取,数据量比较大,鼠标滑到页面最底部,调取一次接口,分批加载;
demo:
<template>
<div>
<!-- 触发弹框的按钮 -->
<el-button @click="dialogVisible = true">打开弹框</el-button>
<!-- 数据加载中的提示 -->
<el-loading v-if="loading" lock text="数据加载中,请稍候..."></el-loading>
<!-- 弹框 -->
<el-dialog
:visible.sync="dialogVisible"
title="大批量数据列表"
@before-close="handleClose"
>
<div class="data-list" ref="dataList" @scroll="handleScroll">
<!-- 使用 v-for 渲染数据列表 -->
<div v-for="(item, index) in items" :key="index" class="data-item">
{{ item }}
</div>
</div>
<!-- 分页控件,点击加载更多 -->
<el-button
slot="footer"
size="small"
@click="loadMore"
:disabled="loading"
>加载更多</el-button
>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false, // 控制弹框显示
loading: false, // 数据加载中
items: [], // 数据列表
currentPage: 1, // 当前页码
pageSize: 200, // 每页数据量
hasMore: true, // 是否还有更多数据
};
},
methods: {
// 加载更多数据
loadMore() {
console.log("调取loadMore方法");
if (!this.hasMore) return;
this.loading = true;
this.currentPage++;
// 模拟从接口获取数据
this.fetchData(this.currentPage, this.pageSize)
.then((data) => {
this.items = this.items.concat(data);
this.loading = false;
// 判断是否还有更多数据
if (data.length < this.pageSize) {
this.hasMore = false;
}
})
.catch((error) => {
console.error("加载数据失败", error);
this.loading = false;
});
},
// 关闭弹框前的回调
handleClose() {
this.items = []; // 清空数据列表
this.currentPage = 1;
this.hasMore = true;
this.loading = false; // 确保关闭弹框时停止加载
},
// 模拟获取数据的方法
fetchData(page, pageSize) {
return new Promise((resolve, reject) => {
// 这里应该是调用你的 API 获取数据
// 以下是一个模拟的数据响应示例
const mockData = new Array(pageSize)
.fill(null)
.map((_, index) => `Item ${(page - 1) * pageSize + index + 1}`);
setTimeout(() => {
resolve(mockData);
}, 1000);
});
},
// 监听滚动事件,当滚动到底部时加载更多数据
// handleScroll() {
// if (this.$refs.dataList && this.$refs.dataList.scroll) {
// const scrollContainer = this.$refs.dataList.scroll;
// if (
// scrollContainer.scrollTop + scrollContainer.clientHeight >=
// scrollContainer.scrollHeight - 10
// ) {
// this.loadMore();
// }
// }
// },
// 监听滚动事件,当滚动到底部时加载更多数据
handleScroll(event) {
// 获取滚动容器的引用
const scrollContainer = event.target || this.$refs.dataList;
// 确保 scrollContainer 是一个有效的 DOM 元素
if (!scrollContainer) return;
// 计算滚动位置
const isAtBottom =
scrollContainer.scrollTop + scrollContainer.clientHeight >=
scrollContainer.scrollHeight - 10;
// 只有在滚动到底部时才调用 loadMore 方法
if (isAtBottom && this.hasMore) {
console.log('zoujinqu')
this.loadMore();
}
},
},
mounted() {
// 监听滚动事件,当滚动到底部时加载更多数据
// this.$refs.dataList.addEventListener('scroll', this.handleScroll);
this.$nextTick(() => {
if (this.$refs.dataList) {
this.$refs.dataList.addEventListener("scroll", this.handleScroll);
}
});
},
beforeDestroy() {
// 组件销毁前移除事件监听
if (this.$refs.dataList) {
this.$refs.dataList.removeEventListener("scroll", this.handleScroll);
}
},
};
</script>
<style scoped>
.data-list {
max-height: 500px; /* 设置一个固定高度 */
overflow-y: auto; /* 允许垂直滚动 */
}
.data-item {
padding: 8px;
border-bottom: 1px solid #eee;
}
</style>
真实项目:
弹框内容是分接口给的数据,分批次加载(其实跟分页是一回事),鼠标滑到最底部,调取一次接口,加载一次数据。
<template>
<div>
<div style="position: relative; transition: all ease 0.5s">
<el-table :data="defectList" style="width: 100%">
<el-table-column prop="logFileName" label="日志信息" :show-overflow-tooltip="true" width="140">
<template slot-scope="scope">
<span class="color-list cursor" @click="logInfo(scope.row.logFileId)">{{ scope.row.logFileName }}</span>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog title="日志详情" :visible.sync="dialogVisible" width="800px" :before-close="closeDialog">
<div class="data-list" ref="dataList" @scroll="handleScroll">
<div>
{{ logDataInfo }}
</div>
</div>
</el-dialog>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { warn, downloadFetchFiles } from '@/utils/common'
import API from '@/api'
import { Base64 } from 'js-base64'
export default Vue.extend({
components: {},
props: {
defectList: {
type: Array,
default: () => []
},
total: {
type: Number,
default: 0
},
onPageChange: {
type: Function,
default: () => {}
}
},
data() {
return {
selectedRow: null,
dialogVisible: false,
logDataInfo: '',
loading: false,
hasMore: true,
currentPage: 1, // 当前页数
pageSize: 50000 // 每页数量,
}
},
mounted() {
this.$nextTick(() => {
if (this.$refs.dataList) {
this.$refs.dataList.addEventListener('scroll', this.handleScroll)
}
})
},
methods: {
logInfo(id: string) {
localStorage.setItem('IDD', id)
this.dialogVisible = true
this.loadMore()
},
// 加载数据
async loadMore() {
try {
if (this.loading || !this.hasMore) return // 如果正在加载或没有更多数据了,则不再发送请求
let id = localStorage.getItem('IDD')
if(this.currentPage - 1 >= this.logTotal) {
return false;
}
const response = await API.Defect.logDetailsData({
page: this.currentPage,
pageSize: this.pageSize,
fileId: id
})
const data = Base64.decode(response.data.list)
if (data) {
this.logDataInfo = data
this.currentPage++ // 当前页数加一
} else {
this.hasMore = false // 没有更多数据了
}
} catch (error) {
warn(error, true)
}
},
// 监听滚动事件,当滚动到底部时加载更多数据
handleScroll(event: any) {
// 获取滚动容器的引用
const scrollContainer = event.target || this.$refs.dataList
// 确保 scrollContainer 是一个有效的 DOM 元素
if (!scrollContainer) return
// 计算滚动位置
const isAtBottom = scrollContainer.scrollTop + scrollContainer.clientHeight >= scrollContainer.scrollHeight - 10
if (isAtBottom && this.hasMore) {
console.log('zoujinqu')
this.loadMore()
}
},
closeDialog() {
this.dialogVisible = false
this.dataList = []
this.loading = false
this.hasMore = true
this.currentPage = 1
}
},
beforeDestroy() {
// 组件销毁前移除事件监听
if (this.$refs.dataList) {
this.$refs.dataList.removeEventListener('scroll', this.handleScroll)
}
}
})
</script>