Files
sgxt_web/src/views/home/model/experience copy 2.vue
2025-11-22 21:59:58 +08:00

227 lines
6.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>