先看展示:
消息滚动
再看代码
<template>
<div
class="scroll-container"
@mouseenter="pauseScroll"
@mouseleave="resumeScroll"
>
<el-table
:data="displayData"
:height="tableHeight"
style="width: 100%"
:row-class-name="tableRowClassName"
border
>
<el-table-column prop="type" label="消息类型" />
<el-table-column prop="content" label="消息内容" />
<el-table-column prop="timestamp" label="创建时间" />
</el-table>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
//这里就是个生成消息数据的函数
function generateRandomMessage() {
// 消息类型配置
const messageTypes = [
{
type: "system",
templates: [
"系统维护通知:服务将于今晚23:00进行升级",
"新功能模块已上线,请前往体验",
"安全提示:检测到异常登录,请立即修改密码",
],
},
{
type: "user",
templates: [
"用户@{{username}} 加入了频道",
"{{username}} 发送了新的文件:{{filename}}",
"{{username}} 提到了你:{{content}}",
],
},
{
type: "warning",
templates: [
"警告:存储空间不足,请清理文件",
"您的账号存在安全风险,请进行身份验证",
"检测到异常操作,已暂时冻结账号",
],
},
{
type: "promotion",
templates: [
"限时优惠:专业版5折起",
"邀请好友得积分,100积分=10元",
"新用户专享礼包已发放至账户",
],
},
];
// 随机选择消息类型
const randomType =
messageTypes[Math.floor(Math.random() * messageTypes.length)];
// 生成随机数据
const randomData = {
username: ["Alice", "Bob", "Charlie", "David"][
Math.floor(Math.random() * 4)
],
filename: ["report.pdf", "design.png", "data.csv"][
Math.floor(Math.random() * 3)
],
content: ["这个项目需要你的帮助", "请查看最新文档", "会议时间需要调整"][
Math.floor(Math.random() * 3)
],
};
// 选择随机模板并替换变量
const template =
randomType.templates[
Math.floor(Math.random() * randomType.templates.length)
];
let messageContent = template.replace(
/{{(\w+)}}/g,
(_, key) => randomData[key] || ""
);
// 生成完整消息对象
return {
id: Date.now(), // 使用时间戳作为唯一ID
type: randomType.type,
content: messageContent,
timestamp: new Date().toISOString(),
sender: randomType.type === "user" ? randomData.username : "System",
};
}
// 创建原始数据
const originalData = ref([]);
for (let i = 0; i < 30; i++) {
originalData.value.push(generateRandomMessage());
}
// 表格显示数据(双倍数据用于循环)
const displayData = computed(() => [
...originalData.value,
...originalData.value, // 克隆一份数据实现无缝衔接 还需要注意的是,一份数据的总高度要大于表格展示的高度,不然会卡顿
]);
// 表格高度
const tableHeight = ref(500);
// 滚动控制标志
const isPaused = ref(false);
// 滚动定时器
let scrollInterval = null;
// 滚动位置偏移量
let scrollOffset = 0;
// 自动滚动函数
const autoScroll = () => {
scrollInterval = setInterval(() => {
if (!isPaused.value) {
const tableBody = document.querySelector(".el-scrollbar__wrap"); //看好需要获取DOM的类名
if (tableBody) {
// 更新滚动位置
scrollOffset += 1;
tableBody.scrollTop = scrollOffset;
// 当滚动到第二份数据末尾时,瞬间跳回第一份数据开头 这里就是让他循环滚动
if (scrollOffset >= tableBody.scrollHeight / 2) {
requestAnimationFrame(() => {
tableBody.scrollTop = 0;
scrollOffset = 0;
});
}
}
}
}, 20);
};
const tableRowClassName = ({ row, rowIndex }) => {
if (row.type === "system") {
return "system-row";
}
if (row.type === "warning") {
return "warning-row";
}
};
// 暂停滚动
const pauseScroll = () => {
isPaused.value = true;
};
// 恢复滚动
const resumeScroll = () => {
isPaused.value = false;
};
// 生命周期钩子
onMounted(() => {
autoScroll();
});
onBeforeUnmount(() => {
clearInterval(scrollInterval);
});
</script>
<style scoped lang="scss">
.scroll-container {
height: 500px;
}
/* 穿透样式 */
::v-deep(.el-table) {
.system-row {
--el-table-tr-bg-color: var(--el-color-success-light-9);
}
}
</style>