Files
sgxt_web/src/views/home/model/experience copy 2.vue

227 lines
6.0 KiB
Vue
Raw Normal View History

2025-11-22 21:59:58 +08:00
<template>
<div class="comom-title" @click="chooseForumPost">
<span class="title">情报论坛</span>
</div>
<div class="comom-cnt" style="height: 300px;">
<div class="zdryBox">
<div class="carousel-container"
@mouseenter="pauseCarousel"
@mouseleave="startCarousel">
<ul class="ryBox" ref="carouselList">
<li v-for="item in displayList" :key="item.id" @click="chooseItem(item)">
<div>{{ item.title }}</div>
<div class="meta-info">{{ item.time }}{{ item.fbrxm }}</div>
<div>{{ item.content }}</div>
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { tbGsxtXxltSelectPage } from '@/api/tbGsxtXxltHf'
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
import {useRouter} from 'vue-router'
const router = useRouter()
// 数据相关
const personList = ref([]);
const displayList = ref([]); // 用于显示的数据列表
const loading = ref(false);
// 轮播相关
const carouselList = ref(null);
const scrollTimer = ref(null);
const scrollSpeed = ref(3000); // 滚动间隔时间(ms)
const itemHeight = ref(106); // 每个item的高度(px) - 与CSS变量保持一致
const currentIndex = ref(0);
const visibleItems = ref(3); // 可见条目数量
// 获取数据
const getList = () => {
loading.value = true;
tbGsxtXxltSelectPage({ pageSize: 10, pageCurrent: 1 }).then(res => {
loading.value = false;
personList.value = res.records || [];
// 复制一份数据到displayList实现无缝滚动效果
displayList.value = [...personList.value, ...personList.value];
}).catch(() => {
loading.value = false;
})
};
// 开始轮播
const startCarousel = () => {
if (scrollTimer.value) return;
scrollTimer.value = setInterval(() => {
scrollToNext();
}, scrollSpeed.value);
};
// 暂停轮播
const pauseCarousel = () => {
if (scrollTimer.value) {
clearInterval(scrollTimer.value);
scrollTimer.value = null;
}
};
// 滚动到下一项
const scrollToNext = () => {
if (!carouselList.value || personList.value.length === 0) return;
currentIndex.value++;
// 实现平滑滚动
const scrollHeight = currentIndex.value * itemHeight.value;
// 设置平滑过渡效果
carouselList.value.style.transition = 'transform 0.5s ease-out';
carouselList.value.style.transform = `translateY(-${scrollHeight}px)`;
// 当滚动到原始数据的末尾时,准备重置位置实现无缝滚动
// 使用personList.length而不是displayList.length确保无缝效果
if (currentIndex.value >= personList.value.length) {
// 确保过渡动画完成后再重置位置设置稍微小于transition时间的值
setTimeout(() => {
// 重置索引和位置,移除过渡效果以避免重置时的视觉跳动
currentIndex.value = 0;
carouselList.value.style.transition = 'none';
carouselList.value.style.transform = 'translateY(0)';
// 在下一帧重新应用过渡效果,确保动画连续性
requestAnimationFrame(() => {
carouselList.value.style.transition = 'transform 0.5s ease-out';
});
}, 490); // 略微小于500ms的过渡时间确保在动画完成后立即重置
}
};
// 点击项
const chooseItem = (item) => {
pauseCarousel(); // 点击时暂停轮播
router.push({
path: '/forumPost',
query: { id: item.id }
})
};
// 添加跳转
const chooseForumPost = () => {
pauseCarousel(); // 点击时暂停轮播
router.push({ path: '/forumPost' })
};
// 生命周期
onMounted(() => {
getList();
// 数据加载后开始轮播
setTimeout(() => {
startCarousel();
}, 1000);
// 监听窗口尺寸变化,调整轮播逻辑
window.addEventListener('resize', handleResize);
});
// 处理窗口尺寸变化
const handleResize = () => {
// 窗口大小改变时可以在这里调整itemHeight等参数
// 也可以暂停并重新开始轮播以适应新尺寸
};
// 组件卸载前清除定时器和事件监听
onBeforeUnmount(() => {
pauseCarousel();
window.removeEventListener('resize', handleResize);
});
</script>
<style>
.el-loading-mask {
background: rgba(0, 0, 0, 0.5);
}
</style>
<style lang="scss" scoped>
@import "@/assets/css/homeScreen.scss";
.zdryBox {
height: 100%;
position: relative;
overflow: hidden;
/* 确保只显示3个条目的高度根据实际内容调整 */
--visible-items: 3;
--item-height: 106px;
--total-height: calc(var(--visible-items) * var(--item-height));
.carousel-container {
height: 100%;
overflow: hidden;
position: relative;
/* 限制显示区域,只显示指定数量的条目 */
max-height: var(--total-height);
box-sizing: border-box;
}
.ryBox {
position: absolute;
top: 0;
left: 0;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
/* 确保在重置位置时不会出现闪烁 */
will-change: transform;
backface-visibility: hidden;
perspective: 1000px;
li {
padding: 12px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
transition: background-color 0.3s;
cursor: pointer;
/* 确保每个项目的高度一致,便于计算 */
height: var(--item-height);
box-sizing: border-box;
&:hover {
background-color: rgba(20, 107, 190, 0.2);
}
> div:first-child {
font-weight: bold;
color: #fff;
margin-bottom: 8px;
font-size: 14px;
/* 标题限制1行超出用省略号 */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta-info {
text-align: right;
color: #83bff6;
font-size: 12px;
margin-bottom: 8px;
}
> div:last-child {
color: rgba(255, 255, 255, 0.8);
font-size: 13px;
line-height: 1.6;
/* 内容限制3行超出用省略号 */
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
</style>