精选模块 · 轮播滑块(carousel-slide)详解
本文档详细说明首页“文章 · 精选模块”的轮播滑块实现与使用方式,涵盖设计理念、目录结构、数据与行为、API、样式、自定义与最佳实践。
设计目标
- 突出高质量内容:基于文章
recommend值筛选与排序。 - 占用更少空间:采用纵向单卡片轮播(vertical slide)。
- 读取友好:4s 自动切换,支持鼠标悬停暂停。
- 极简美观:只呈现“标题 + 简介”,搭配轻量玻璃拟态与细腻动效。
- 开箱即用:已封装懒加载包装组件,可直接放入页面。
目录结构
app/components/widget/FeaturedArticlesCarousel.vue:轮播主体组件(本模块核心)。app/components/widget/LazyWidgetFeaturedArticlesCarousel.vue:懒加载包装组件。app/composables/useFeaturedArticles.ts:精选文章数据获取与变体函数。
核心代码
1. 轮播主体组件 (FeaturedArticlesCarousel.vue)
关键逻辑:
<script setup lang="ts">
const { data: featuredArticles } = await useFeaturedArticles(5, 1)
const currentIndex = ref(0)
const isAutoPlay = ref(true)
const isTransitioning = ref(true)
const nextSlide = () => {
currentIndex.value = currentIndex.value + 1
if (currentIndex.value >= processedArticles.value.length) {
setTimeout(() => {
isTransitioning.value = false
currentIndex.value = 0
setTimeout(() => { isTransitioning.value = true }, 50)
}, 2200)
}
}
</script>
<template>
<div class="carousel-track" :style="{
transform: `translateY(-${currentIndex * 100}%)`,
transition: isTransitioning ? 'transform 2.2s cubic-bezier(0.25, 0.46, 0.45, 0.94)' : 'none'
}">
<div v-for="article in processedArticles" class="carousel-slide">
<ZRawLink :to="article.path" class="featured-card">
<div class="card-content">
<h3 class="card-title">{{ article.title }}</h3>
<p class="card-description">{{ article.description }}</p>
</div>
</ZRawLink>
</div>
</div>
</template>
2. 懒加载包装组件 (LazyWidgetFeaturedArticlesCarousel.vue)
<script setup lang="ts">
const FeaturedArticlesCarousel = defineAsyncComponent(() => import('./FeaturedArticlesCarousel.vue'))
</script>
<template>
<Suspense>
<FeaturedArticlesCarousel />
<template #fallback>加载中...</template>
</Suspense>
</template>
3. 数据获取 Composable (useFeaturedArticles.ts)
export function useFeaturedArticles(limit = 5, minRecommend = 1) {
return useAsyncData(`featured-articles-${limit}-${minRecommend}`,
() => queryCollection('content')
.where('stem', 'LIKE', 'posts/%')
.where('recommend', '>=', minRecommend)
.select('categories', 'date', 'description', 'image', 'path', 'readingTime', 'recommend', 'title', 'type', 'updated')
.all()
.then(articles => {
const sorted = articles.sort((a, b) => {
const recommendDiff = (b.recommend || 0) - (a.recommend || 0)
if (recommendDiff !== 0) return recommendDiff
return new Date(b.date || 0).getTime() - new Date(a.date || 0).getTime()
})
return sorted.slice(0, limit)
}),
{ default: () => [] as ArticleProps[] }
)
}
数据来源与规则
- 数据来自
content集合中路径以posts/开头的文章。 - 通过
recommend >= minRecommend筛选;默认minRecommend = 1。 - 排序规则:先按
recommend降序;若相等,再按date降序。 - 默认最多返回 5 篇,可自定义数量与最小推荐值。
可用字段(已在组件内使用):categories、date、description、image、path、readingTime、recommend、title、type、updated。
轮播行为设计
- 布局:纵向单卡片容器,高度 5rem(移动端 4rem)。
- 自动播放:默认每 4000ms 切换一次。
- 悬停暂停:
mouseenter暂停、mouseleave恢复。 - 过渡:
transform: translateY(),默认 2.2s cubic-bezier 缓动。 - 无缝循环:在轨道末尾复制第一张,动画结束后取消过渡瞬时归位为第 1 张,再恢复过渡,视觉无缝。
- 空态:当无精选文章时显示占位提示。
快速开始
在任意页面模板中引入懒加载包装组件(推荐):
<template>
<div class="featured-section">
<LazyWidgetFeaturedArticlesCarousel />
</div>
</template>
或直接使用主体组件(同步加载):
<template> <FeaturedArticlesCarousel /> </template>
API 与扩展点
组件
FeaturedArticlesCarousel- Props:无(当前版本)。
- 插槽:无。
- 事件:无。
- 说明:开箱即用的精选轮播组件,内部完成数据拉取与展示逻辑。
LazyWidgetFeaturedArticlesCarousel- 用途:用
Suspense + defineAsyncComponent对主体组件懒加载,并提供加载占位。
- 用途:用
Composables
位于 app/composables/useFeaturedArticles.ts:
useFeaturedArticles(limit = 5, minRecommend = 1):按推荐值筛选与排序,默认 5 篇、recommend >= 1。usePopularArticles(limit = 3):热门(基于推荐值),等价于useFeaturedArticles(limit, 1)。useLatestFeaturedArticles(limit = 3):最新精选(按时间降序)。useCategoryFeaturedArticles(category: string, limit = 3):某分类的精选文章。
示例:
const { data: featuredArticles } = await useFeaturedArticles(5, 1)
样式类参考
- 容器:
.featured-carousel-main、.carousel-container、.carousel-header、.featured-title、.featured-text、.megaphone-container。 - 轮播:
.carousel-wrapper(含玻璃拟态与立体边框)、.carousel-track、.carousel-slide。 - 卡片:
.featured-card、.card-content、.card-title-row、.card-title、.recommend-badge、.card-description。 - 空态:
.no-featured、.no-featured-icon、.no-featured-text、.no-featured-hint。 - 响应式:
@media (max-width: 768px)下针对高度、圆角、阴影与字号做了收敛。
适配与可访问性
- 响应式:移动端高度缩小至 4rem,间距/阴影同步收敛。
- 交互:悬停暂停可避免阅读被打断。
- 链接:使用
ZRawLink跳转目标文章路径。
最终效果


评论区
评论加载中...