<div class="wh-full">
<el-`table`
v-bind="$attrs"
:data="displayData"
:height="height"
ref="tableRef"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<slot />
</el-table>
</div>
</template>
<script lang="ts" setup>
import { ref, onUnmounted, watch, nextTick, computed } from "vue";
interface Props {
data: any[]; // 表格数据
height: string | number; // 表格高度
autoStart?: boolean; // 是否自动滚动
autoLength?: number; // 自动滚动时,数据长度小于等于此值时不滚动
scrollInterval?: number; // 控制滚动频率
}
const props = withDefaults(defineProps<Props>(), {
data: () => [],
height: "100%",
autoStart: true,
autoLength: 4,
scrollInterval: 30
});
const tableRef = ref();
const isScrolling = ref(false);
const scrollTimerId = ref<number | null>(null);
const animationFrameId = ref<number | null>(null);
// 计算展示数据
const displayData = computed(() => {
if (props.data.length <= props.autoLength) return props.data;
return [...props.data, ...props.data];
});
// 清理定时器和动画帧
const clearTimers = () => {
if (scrollTimerId.value) {
clearTimeout(scrollTimerId.value);
scrollTimerId.value = null;
}
if (animationFrameId.value) {
cancelAnimationFrame(animationFrameId.value);
animationFrameId.value = null;
}
};
// 获取表格容器元素
const getTableWrapper = () => {
const bodyWrapper = tableRef.value?.$refs.bodyWrapper;
return bodyWrapper?.firstElementChild?.firstElementChild;
};
// 滚动处理函数
const handleScroll = (tableWrapper: HTMLElement) => {
if (!tableWrapper || !isScrolling.value) return;
tableWrapper.scrollTop += 1;
if (tableWrapper.scrollTop + tableWrapper.clientHeight >= tableWrapper.scrollHeight) {
tableWrapper.scrollTop = tableWrapper.scrollTop - tableWrapper.scrollHeight / 2;
}
scrollTimerId.value = window.setTimeout(() => {
animationFrameId.value = requestAnimationFrame(() => handleScroll(tableWrapper));
}, props.scrollInterval);
};
// 开始滚动
const startScroll = () => {
const tableWrapper = getTableWrapper();
if (!tableWrapper || props.data.length <= props.autoLength) return;
if (tableWrapper.scrollHeight / 2 < tableWrapper.clientHeight) return;
isScrolling.value = true;
handleScroll(tableWrapper);
};
// 停止滚动
const stopScroll = () => {
isScrolling.value = false;
clearTimers();
};
// 鼠标事件处理
const handleMouseEnter = () => stopScroll();
const handleMouseLeave = () => startScroll();
// 监听数据变化
watch(
() => props.data,
newData => {
if (newData?.length > 0 && props.autoStart) {
nextTick(() => {
setTimeout(() => {
startScroll();
}, 1000);
});
}
},
{ immediate: true }
);
// 组件卸载时清理
onUnmounted(() => {
stopScroll();
});
</script>
<style scoped lang="scss"></style>