背景: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-buttonslot="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 = truethis.loadMore()},// 加载数据async loadMore() {try {if (this.loading || !this.hasMore) return // 如果正在加载或没有更多数据了,则不再发送请求let id = localStorage.getItem('IDD')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 = datathis.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 - 10if (isAtBottom && this.hasMore) {console.log('zoujinqu')this.loadMore()}},closeDialog() {this.dialogVisible = falsethis.dataList = []this.loading = falsethis.hasMore = truethis.currentPage = 1}},beforeDestroy() {// 组件销毁前移除事件监听if (this.$refs.dataList) {this.$refs.dataList.removeEventListener('scroll', this.handleScroll)}}
})
</script>