Carousel 走马灯
概述
Carousel 走马灯组件用于在有限空间内,循环播放同一类型的图片、文字等内容。常用于轮播图、产品展示、广告位等场景,提供了自动播放、手动切换、指示器等功能。
学习目标
- 掌握 Carousel 组件的基础用法
- 学会配置自动播放和切换效果
- 理解指示器和切换箭头的使用
- 掌握垂直方向和卡片化的走马灯
- 了解 Carousel 组件的 API 和最佳实践
基础用法
基础走马灯
适用广泛的基础用法。结合使用 el-carousel
和 el-carousel-item
标签就得到了一个走马灯。幻灯片的内容是任意的,需要放在 el-carousel-item
标签中。默认情况下,在鼠标 hover 底部的指示器时就会触发切换。通过设置 trigger
属性为 click
,可以达到点击触发的效果。
<template>
<div class="carousel-demo">
<h3>基础走马灯</h3>
<el-carousel height="150px">
<el-carousel-item v-for="item in 4" :key="item">
<h3 class="small" justify="center">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style scoped>
.el-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 150px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
指示器
可以将指示器的显示位置设置在容器外部。indicator-position
属性定义了指示器的位置。默认情况下,它会显示在走马灯内部,设置为 outside
则会显示在外部;设置为 none
则不会显示指示器。
<template>
<div class="indicator-demo">
<h3>外部指示器</h3>
<el-carousel indicator-position="outside">
<el-carousel-item v-for="item in 4" :key="item">
<h3 class="medium" justify="center">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style scoped>
.el-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 200px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
切换箭头
可以设置切换箭头的显示时机。arrow
属性定义了切换箭头的显示时机。默认情况下,切换箭头只有在鼠标 hover 到走马灯上时才会显示;若将 arrow
设置为 always
,则会一直显示;设置为 never
,则会一直隐藏。
<template>
<div class="arrow-demo">
<h3>切换箭头</h3>
<el-carousel :interval="4000" arrow="always">
<el-carousel-item v-for="item in 4" :key="item">
<h3 class="medium" justify="center">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style scoped>
.el-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 200px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
卡片化
当页面宽度方向空间空余,但高度方向空间匮乏时,可使用卡片风格。将 type
设置为 card
即可启用卡片模式。从性能的角度考虑,当切换到卡片模式时,只有两侧的卡片会渲染。
<template>
<div class="card-demo">
<h3>卡片化</h3>
<el-carousel :interval="4000" type="card" height="200px">
<el-carousel-item v-for="item in 6" :key="item">
<h3 class="medium" justify="center">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style scoped>
.el-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 200px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
方向
默认情况下,direction
为 horizontal
。通过设置 direction
为 vertical
来让走马灯在垂直方向上显示。
<template>
<div class="vertical-demo">
<h3>垂直方向</h3>
<el-carousel height="200px" direction="vertical" :autoplay="false">
<el-carousel-item v-for="item in 3" :key="item">
<h3 class="medium" justify="center">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style scoped>
.el-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 200px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
实际应用示例
图片轮播
<template>
<div class="image-carousel-demo">
<h3>图片轮播</h3>
<el-carousel
:interval="5000"
arrow="always"
indicator-position="outside"
height="300px"
>
<el-carousel-item v-for="(image, index) in images" :key="index">
<div class="carousel-image">
<img :src="image.url" :alt="image.title" />
<div class="image-overlay">
<h4>{{ image.title }}</h4>
<p>{{ image.description }}</p>
</div>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script setup>
import { ref } from 'vue'
const images = ref([
{
url: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
title: '美味汉堡',
description: '新鲜制作,口感丰富'
},
{
url: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
title: '精选食材',
description: '优质原料,健康美味'
},
{
url: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
title: '特色套餐',
description: '搭配饮品,超值享受'
}
])
</script>
<style scoped>
.carousel-image {
position: relative;
width: 100%;
height: 100%;
}
.carousel-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.image-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
color: white;
padding: 20px;
}
.image-overlay h4 {
margin: 0 0 8px 0;
font-size: 18px;
}
.image-overlay p {
margin: 0;
font-size: 14px;
opacity: 0.9;
}
</style>
产品展示轮播
<template>
<div class="product-carousel-demo">
<h3>产品展示轮播</h3>
<el-carousel
type="card"
height="250px"
:autoplay="false"
@change="handleCarouselChange"
>
<el-carousel-item v-for="product in products" :key="product.id">
<div class="product-card">
<div class="product-image">
<img :src="product.image" :alt="product.name" />
</div>
<div class="product-info">
<h4>{{ product.name }}</h4>
<p class="price">¥{{ product.price }}</p>
<el-rate v-model="product.rating" disabled size="small" />
</div>
</div>
</el-carousel-item>
</el-carousel>
<div class="current-product" v-if="currentProduct">
<h4>当前展示:{{ currentProduct.name }}</h4>
<p>{{ currentProduct.description }}</p>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const products = ref([
{
id: 1,
name: 'MacBook Pro',
price: 12999,
rating: 5,
image: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
description: '强大的专业级笔记本电脑,适合开发和设计工作'
},
{
id: 2,
name: 'iPhone 15 Pro',
price: 8999,
rating: 5,
image: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
description: '最新的智能手机,拍照和性能都很出色'
},
{
id: 3,
name: 'iPad Air',
price: 4599,
rating: 4,
image: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
description: '轻薄便携的平板电脑,适合娱乐和轻办公'
},
{
id: 4,
name: 'Apple Watch',
price: 2999,
rating: 4,
image: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
description: '智能手表,健康监测和运动追踪功能强大'
}
])
const currentProduct = ref(null)
const handleCarouselChange = (index) => {
currentProduct.value = products.value[index]
}
onMounted(() => {
currentProduct.value = products.value[0]
})
</script>
<style scoped>
.product-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
height: 100%;
display: flex;
flex-direction: column;
}
.product-image {
height: 150px;
overflow: hidden;
}
.product-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.product-info {
padding: 16px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.product-info h4 {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: 600;
}
.price {
margin: 8px 0;
font-size: 18px;
font-weight: bold;
color: #f56c6c;
}
.current-product {
margin-top: 20px;
padding: 16px;
background: #f5f7fa;
border-radius: 8px;
}
.current-product h4 {
margin: 0 0 8px 0;
color: #409eff;
}
.current-product p {
margin: 0;
color: #666;
}
</style>
新闻公告轮播
<template>
<div class="news-carousel-demo">
<h3>新闻公告轮播</h3>
<el-carousel
direction="vertical"
height="120px"
:autoplay="true"
:interval="3000"
indicator-position="none"
arrow="never"
>
<el-carousel-item v-for="news in newsList" :key="news.id">
<div class="news-item" @click="handleNewsClick(news)">
<div class="news-content">
<h4>{{ news.title }}</h4>
<p>{{ news.summary }}</p>
<span class="news-date">{{ news.date }}</span>
</div>
<div class="news-type">
<el-tag :type="news.type === 'important' ? 'danger' : 'info'" size="small">
{{ news.type === 'important' ? '重要' : '通知' }}
</el-tag>
</div>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const newsList = ref([
{
id: 1,
title: '系统维护通知',
summary: '系统将于今晚22:00-24:00进行维护升级',
date: '2024-01-15',
type: 'important'
},
{
id: 2,
title: '新功能上线',
summary: '数据导出功能已上线,支持多种格式导出',
date: '2024-01-14',
type: 'normal'
},
{
id: 3,
title: '安全提醒',
summary: '请定期更新密码,确保账户安全',
date: '2024-01-13',
type: 'important'
},
{
id: 4,
title: '使用指南',
summary: '新用户使用指南已更新,欢迎查看',
date: '2024-01-12',
type: 'normal'
}
])
const handleNewsClick = (news) => {
ElMessage.info(`点击了新闻:${news.title}`)
}
</script>
<style scoped>
.news-item {
display: flex;
align-items: center;
padding: 16px;
background: white;
border-radius: 8px;
margin: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.3s;
}
.news-item:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.news-content {
flex: 1;
}
.news-content h4 {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
color: #303133;
}
.news-content p {
margin: 0 0 8px 0;
font-size: 14px;
color: #606266;
line-height: 1.4;
}
.news-date {
font-size: 12px;
color: #909399;
}
.news-type {
margin-left: 16px;
}
</style>
API 文档
Carousel Attributes
属性名 | 说明 | 类型 | 默认值 |
---|---|---|---|
height | 走马灯的高度 | string | — |
initial-index | 初始状态激活的幻灯片的索引,从 0 开始 | number | 0 |
trigger | 指示器的触发方式 | enum: hover / click | hover |
autoplay | 是否自动切换 | boolean | true |
interval | 自动切换的时间间隔,单位为毫秒 | number | 3000 |
indicator-position | 指示器的位置 | enum: none / outside | — |
arrow | 切换箭头的显示时机 | enum: always / hover / never | hover |
type | 走马灯的类型 | enum: card | — |
loop | 是否循环显示 | boolean | true |
direction | 走马灯展示的方向 | enum: horizontal / vertical | horizontal |
pause-on-hover | 鼠标悬浮时暂停自动切换 | boolean | true |
Carousel Events
事件名 | 说明 | 回调参数 |
---|---|---|
change | 幻灯片切换时触发 | 目前激活的幻灯片的索引,原幻灯片的索引 |
Carousel Methods
方法名 | 说明 | 参数 |
---|---|---|
setActiveItem | 手动切换幻灯片 | 需要切换的幻灯片的索引,从 0 开始;或相应 el-carousel-item 的 name 属性值 |
prev | 切换至上一张幻灯片 | — |
next | 切换至下一张幻灯片 | — |
Carousel-Item Attributes
属性名 | 说明 | 类型 | 默认值 |
---|---|---|---|
name | 幻灯片的名字,可用作 setActiveItem 的参数 | string | — |
label | 该幻灯片所对应指示器的文本 | string | — |
最佳实践
性能优化
- 图片懒加载:对于图片轮播,使用懒加载减少初始加载时间
- 合理的切换间隔:根据内容类型设置合适的自动切换时间
- 卡片模式优化:卡片模式下只渲染必要的幻灯片
用户体验
- 暂停控制:鼠标悬浮时暂停自动播放
- 指示器设计:提供清晰的当前位置指示
- 触摸支持:在移动设备上支持滑动切换
可访问性
- 键盘导航:支持键盘方向键切换
- 屏幕阅读器:为图片提供 alt 属性
- 焦点管理:合理管理焦点状态
响应式设计
- 断点适配:在不同屏幕尺寸下调整显示方式
- 触摸友好:在移动设备上优化触摸体验
- 内容适配:确保内容在各种设备上都能正常显示
常见问题
1. 自动播放不工作
问题:走马灯不会自动切换
解决方案:
- 检查
autoplay
属性是否设置为true
- 确认
interval
时间间隔设置合理 - 检查是否有 JavaScript 错误阻止了执行
2. 图片显示异常
问题:图片在走马灯中显示变形或不完整
解决方案:
- 使用
object-fit: cover
保持图片比例 - 设置合适的容器高度
- 确保图片尺寸适当
3. 指示器位置问题
问题:指示器显示位置不符合预期
解决方案:
- 检查
indicator-position
属性设置 - 调整容器的 CSS 样式
- 确保有足够的空间显示指示器
4. 卡片模式显示问题
问题:卡片模式下显示效果不佳
解决方案:
- 确保容器宽度足够
- 调整卡片内容的样式
- 检查是否有 CSS 冲突
总结
Carousel 走马灯组件是一个功能丰富的轮播组件,支持多种显示模式和交互方式。通过合理配置属性和样式,可以创建出适合不同场景的轮播效果。在实际应用中,需要注意性能优化、用户体验和可访问性等方面的最佳实践。