Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
stdj_h5
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Authored by
hookehuyr
2025-11-04 12:17:58 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
e4072accb5269899f301244a528485dd2c69cb7e
e4072acc
1 parent
dbd3f403
refactor(轮播组件): 重构新闻轮播逻辑实现无缝滚动
移除克隆项动态增减逻辑,改用固定克隆首尾项的方式 简化轮播位置更新和动画控制逻辑
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
45 additions
and
65 deletions
src/views/Home.vue
src/views/Home.vue
View file @
e4072ac
...
...
@@ -118,7 +118,7 @@
<!-- 轮播容器 -->
<div class="news-carousel-container">
<div class="news-carousel" ref="newsCarousel">
<div class="news-item" v-for="(item, index) in
n
ewsItems" :key="index" @click="handleNewsClick(item)">
<div class="news-item" v-for="(item, index) in
displayN
ewsItems" :key="index" @click="handleNewsClick(item)">
<div class="news-image">
<img :src="item.image" :alt="item.title">
</div>
...
...
@@ -136,14 +136,12 @@
src="https://cdn.ipadbiz.cn/stdj/images/home/%E4%B8%8A@2x.png"
alt="上一张"
@click="prevSlide"
:class="{ disabled: currentSlide === 0 }"
>
<img
class="nav-btn next-btn"
src="https://cdn.ipadbiz.cn/stdj/images/home/%E4%B8%8B@2x.png"
alt="下一张"
@click="nextSlide"
:class="{ disabled: isTransitioning }"
>
</div>
</div>
...
...
@@ -276,6 +274,11 @@ onMounted(async () => {
image: item.photo || '',
post_link: item.post_link || '',
})) || [];
// 初始化轮播位置
nextTick(() => {
updateCarouselPosition(false)
})
}
})
...
...
@@ -317,59 +320,61 @@ const viewMore = (type, item) => {
// 新闻轮播相关逻辑
const newsCarousel = ref(null)
const currentSlide = ref(
0)
const currentSlide = ref(
1) // 从1开始,因为0是克隆的最后一项
const isTransitioning = ref(false)
const hasTailClone = ref(false)
// 新闻数据
const newsItems = ref([])
// 原始长度用于判断“最后一张”的逻辑
const initialLength = ref(newsItems.value.length)
const displayNewsItems = computed(() => {
if (newsItems.value.length === 0) {
return []
}
// 克隆第一项和最后一项以实现无缝滚动
return [newsItems.value[newsItems.value.length - 1], ...newsItems.value, newsItems.value[0]]
})
// 上一张
const prevSlide = () => {
if (currentSlide.value > 0) {
currentSlide.value--
// 离开最后一张时移除尾部克隆,避免轨道长度异常
if (hasTailClone.value && currentSlide.value < initialLength.value - 1) {
newsItems.value.pop()
hasTailClone.value = false
}
updateCarouselPosition()
if (isTransitioning.value) return
isTransitioning.value = true
currentSlide.value--
updateCarouselPosition()
if (currentSlide.value === 0) {
setTimeout(() => {
isTransitioning.value = false
currentSlide.value = newsItems.value.length
updateCarouselPosition(false) // 无动画地跳转
}, 300) // 等待过渡动画完成
} else {
setTimeout(() => {
isTransitioning.value = false
}, 300)
}
}
// 下一张
const nextSlide = () => {
if (isTransitioning.value) return
// 若还未到原始最后一张,正常前进
if (currentSlide.value < initialLength.value - 1) {
currentSlide.value++
// 当抵达原始最后一张时,预先追加尾部克隆以填充右侧空白
if (currentSlide.value === initialLength.value - 1 && !hasTailClone.value) {
newsItems.value.push(newsItems.value[0])
hasTailClone.value = true
}
isTransitioning.value = true
attachTransitionEndOnce(false)
updateCarouselPosition()
isTransitioning.value = true
currentSlide.value++
updateCarouselPosition()
if (currentSlide.value === displayNewsItems.value.length - 1) {
setTimeout(() => {
isTransitioning.value = false
currentSlide.value = 1
updateCarouselPosition(false) // 无动画地跳转
}, 300) // 等待过渡动画完成
} else {
// 处于原始最后一张:使用尾部克隆进行无缝循环
if (!hasTailClone.value) {
newsItems.value.push(newsItems.value[0])
hasTailClone.value = true
}
currentSlide.value++
isTransitioning.value = true
attachTransitionEndOnce(true)
updateCarouselPosition()
setTimeout(() => {
isTransitioning.value = false
}, 300)
}
}
// 更新轮播位置
:按卡片宽度+间距进行像素级位移
const updateCarouselPosition = () => {
// 更新轮播位置
const updateCarouselPosition = (
animated = true
) => {
const carouselEl = newsCarousel.value
if (!carouselEl) return
...
...
@@ -384,35 +389,10 @@ const updateCarouselPosition = () => {
const gapPx = parseFloat(gapStr) || 8
const distance = currentSlide.value * (itemWidth + gapPx)
carouselEl.style.transition = animated ? 'transform 0.3s ease' : 'none'
carouselEl.style.transform = `translateX(-${distance}px)`
}
// 动画结束后复位(如处于无缝循环场景)
const attachTransitionEndOnce = (looping) => {
const el = newsCarousel.value
if (!el) {
isTransitioning.value = false
return
}
const handler = () => {
el.removeEventListener('transitionend', handler)
if (looping) {
const prevTransition = el.style.transition
el.style.transition = 'none'
// 移除临时克隆,重置到第一张
newsItems.value.pop()
hasTailClone.value = false
currentSlide.value = 0
updateCarouselPosition()
// 强制重绘后恢复过渡
void el.offsetHeight
el.style.transition = prevTransition || 'transform 0.3s ease'
}
isTransitioning.value = false
}
el.addEventListener('transitionend', handler)
}
// 处理新闻点击事件
const handleNewsClick = (item) => {
// 这里可以添加跳转到新闻详情页面的逻辑
...
...
Please
register
or
login
to post a comment