我自己写了一个无缝滚动组件,你可以拿去试一试 { stRef.value.init(); }, 50); 2.如果需要重置滚动高度 stRef.value.scrollTop(0); 3.如果有分页,paging中的三个数据,是用来判断是否已加载完成的,如果不需要分页:paging="false" 详情 {{record[column.dataIndex]}} const _d = reactive({ table: { head: [ {title: '制造单位', dataIndex: 'organization_name'}, {title: '设备类别', dataIndex: 'name'}, {title: '操作', dataIndex: 'actions'}, ], data: [] }, paging: { current: 1, pageSize: 15, total: 0 } }) function search() { _d.paging.current = 1; _d.table.data = []; getData(); } function getNext() { _d.paging.current++; getData(); } // 获取列表 function getData() { d.loading = true; let params = { pageCurrent: _d.paging.current, pageRows: _d.paging.pageSize, areaCode: _d.areaCode } http.postAction(CLOUD_STAT+"onlineData/getCodeEquipmentList", params).then(res => { _d.paging.total = res.rowSum; // 注意:必须要设置total let list = res.rowDatas; if(_d.paging.current == 1) { _d.table.data = [...list]; } else { _d.table.data.push(...list); } }).finally(() => { _d.loading = false; }) } --> {{item.title}} {{aItem[bItem.dataIndex]}} 正在加载中 {{props.table.data.length ? '没有更多了' : '暂无数据'}} 暂无数据 import { reactive, ref, onMounted, useSlots, computed, watch } from 'vue' import { LoadingOutlined } from '@ant-design/icons-vue'; const scrollWrapperRef = ref(); const scrollContentRef = ref(); const slots = useSlots(); const emits = defineEmits(['next']); const props = defineProps({ // 包裹成高度 height: { type: String, default: '685px' }, table: { type: Object, default: () => ({ head: [], data: [] }) }, // 如果返回false,表示不分页 paging: { type: [Object, Boolean], default: () => ({ current: 1, pageSize: 15, total: 0 }) }, // 表头样式 headerTrStyle: { type: Object, default: () => ({}) }, // 表身样式 bodyTrStyle:{ type: Object, default: () => ({}) }, // td样式 tdStyle: { type: Object, default: () => ({}) } }) const _d = reactive({ headPr: 0 }) const notEnd = computed(() => { return props.paging ? props.paging.current*props.paging.pageSize props.table.data.length, () => { setTimeout(() => { if(scrollContentRef.value && scrollWrapperRef.value) { if(scrollContentRef.value && scrollWrapperRef.value) { _d.headPr = scrollContentRef.value.clientHeight > scrollWrapperRef.value.clientHeight ? '3px' : 0 } else { _d.headPr = 0; } } }, 100) }, { immediate: true }) onMounted(() => { oScroll.init() }) // 滚动对象 const oScroll = { oWrapper: null, oContent: null, wrapperHeight: 0, init() { console.log('初始化'); oScroll.oWrapper = scrollWrapperRef.value; if(!oScroll.oWrapper) { return; } oScroll.oContent = scrollContentRef.value; oScroll.wrapperHeight = oScroll.oWrapper.clientHeight; // 设置滚动事件 let scrollTime = 0; oScroll.oWrapper.onscroll = (params) => { if(notEnd.value && oScroll.isScrollBottom(params.target.scrollTop)) { let currentTime = new Date().getTime(); if(currentTime - scrollTime > 500) { // 0.5秒内只能触发一次 scrollTime = currentTime; console.log('触发'); emits('next'); } } } }, // 判断滚动是否触底 isScrollBottom(scrollTop) { let contentHeight = oScroll.oContent.clientHeight; if(contentHeight - oScroll.wrapperHeight .t-scroll-table { color: #fff; display: flex; flex-direction: column; font-size: 14px; .t-header { .tr { background: #05314A; } } .t-body { flex: 1; height: 0; .tr { margin-top: 10px; background: #07263B; } } .tr { display: flex; .td { flex: 1; line-height: 42px; padding: 0 16px; height: 42px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } } .scroll-wrapper { height: 100%; overflow: auto; &::-webkit-scrollbar { width: 3px; } } .table-tip { margin-top: 5px; height: 30px; display: flex; align-items: center; justify-content: center; color: #aaa; } 下面是我在一个弹窗中使用的示例 {{oSimple.unitName(record[column.dataIndex])}} {{record[column.dataIndex]}} import { reactive, ref, onMounted } from 'vue' import tScrollTable from "./modules/tScrollTable/index.vue"; import * as echarts from "echarts"; import dayjs from "dayjs"; import { CLOUD_STAT } from "@/api"; import { http } from "qlrz-service"; import {oSimple} from "@/utils/Tools.js"; const stRef = ref(); const _d = reactive({ visible: false, areaCode: '', table: { head: [ {title: '制造单位', dataIndex: 'organization_name'}, {title: '设备类别', dataIndex: 'name'}, {title: '设备代码', dataIndex: 'equipment_code'}, {title: '设备名称', dataIndex: 'device_name'}, {title: '安全码', dataIndex: 'ewm'}, ], data: [] }, paging: { current: 1, pageSize: 15, total: 0 } }) onMounted(() => { }) function open(areaCode) { _d.areaCode = areaCode || ''; _d.visible = true; // 初始化 setTimeout(() => { stRef.value.init(); }, 50); search(); } function search() { _d.paging.current = 1; _d.table.data = []; getData(); } function getNext() { _d.paging.current++; getData(); } // 获取列表 function getData() { _d.loading = true; let params = { pageCurrent: _d.paging.current, pageRows: _d.paging.pageSize, areaCode: _d.areaCode } http.postAction(CLOUD_STAT+"onlineData/getCodeEquipmentList", params).then(res => { _d.paging.total = res.rowSum; let list = res.rowDatas; if(_d.paging.current == 1) { _d.table.data = [...list]; } else { _d.table.data.push(...list); } }).finally(() => { _d.loading = false; }) } defineExpose({ open }) .ewm { width: 28px; height: 28px; }