基于css的Grid布局和vue实现点击左移右移轮播过渡动画效果
直接上代码,以下代码基于vue2,需要Vue3或者react可以使用国内直连GPT/Claude来帮你转换下
代码如下:
// ScrollCardsGrid.vue
<template>
<div class="scroll-cards-container">
<!-- 左箭头 -->
<div v-show="showLeftArrow" class="scroll-arrow left-arrow" @click="handleScrollLeft">
<i class="arrow-icon">←</i>
</div>
<!-- 卡片容器 -->
<div class="cards-container" ref="cardsContainer" @scroll="handleScroll">
<div class="cards-grid">
<div v-for="(card, index) in cards" :key="index" class="card">
<div class="card-content">
<img :src="card.icon" class="card-icon" :alt="card.title" />
<div class="card-info">
<h3 class="card-title">{{ card.title }}</h3>
<p class="card-description">{{ card.description }}</p>
</div>
</div>
</div>
</div>
</div>
<!-- 右箭头 -->
<div v-show="showRightArrow" class="scroll-arrow right-arrow" @click="handleScrollRight">
<i class="arrow-icon">→</i>
</div>
</div>
</template>
<script>
export default {
name: 'ScrollCardsGrid',
data() {
return {
showLeftArrow: false,
showRightArrow: false,
scrollStep: 300,
cards: [
{
icon: '/path/to/llama.png',
title: 'Llama-3.1-405B',
description: '作为Meta的Llama 3.1系列的巅峰之作...'
},
{
icon: '/path/to/claude.png',
title: 'Claude-3.5-Hai',
description: 'The latest generation of Anthropic\'s fastest...'
},
{
icon: '/path/to/chatgpt.png',
title: 'ChatGPT-4o-La',
description: 'OpenAI的最强大的模型...'
},
{
icon: '/path/to/gpt4.png',
title: 'GPT-4o-Mini',
description: 'OpenAI的最新模型...'
},
{
icon: '/path/to/gemini.png',
title: 'Gemini-1.5-Pro',
description: 'Google的Gemini系列多模态模型...'
},
{
icon: '/path/to/mistral.png',
title: 'Mistral-Medium',
description: 'Mistral AI的中等大小模型...'
},
{
icon: '/path/to/gemini-flash.png',
title: 'Gemini-1.5-Flash',
description: 'Powered by gemini-1.5-flash-002...'
},
{
icon: '/path/to/llama70b.png',
title: 'Llama-3.1-70B',
description: '作为Meta的Llama 3.1系列的中型成员...'
}
]
}
},
mounted() {
this.checkArrows()
window.addEventListener('resize', this.checkArrows)
},
beforeDestroy() {
window.removeEventListener('resize', this.checkArrows)
},
methods: {
checkArrows() {
const container = this.$refs.cardsContainer
if (!container) return
this.showLeftArrow = container.scrollLeft > 0
this.showRightArrow =
container.scrollLeft < (container.scrollWidth - container.clientWidth)
},
handleScroll() {
this.checkArrows()
},
handleScrollLeft() {
const container = this.$refs.cardsContainer
container.scrollBy({
left: -this.scrollStep,
behavior: 'smooth'
})
},
handleScrollRight() {
const container = this.$refs.cardsContainer
container.scrollBy({
left: this.scrollStep,
behavior: 'smooth'
})
}
}
}
</script>
<style scoped>
.scroll-cards-container {
position: relative;
width: 600px;
margin: 0 auto;
margin-top: 200px;
display: flex;
align-items: center;
}
.cards-container {
width: 100%;
overflow-x: auto;
scroll-behavior: smooth;
/* 隐藏滚动条但保持功能 */
scrollbar-width: none;
-ms-overflow-style: none;
padding: 16px 0;
}
.cards-container::-webkit-scrollbar {
display: none;
}
.cards-grid {
display: grid;
/* 固定两行 */
grid-template-rows: repeat(2, 1fr);
/* 自动填充列,每列最小宽度280px */
grid-auto-flow: column;
grid-auto-columns: 280px;
gap: 16px;
padding: 0 16px;
}
.card {
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
/* 确保卡片高度一致 */
height: 88px;
box-sizing: border-box;
}
.card-content {
display: flex;
gap: 12px;
height: 100%;
}
.card-icon {
width: 48px;
height: 48px;
border-radius: 8px;
object-fit: cover;
}
.card-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.card-title {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
line-height: 1.2;
}
.card-description {
margin: 0;
font-size: 14px;
color: #6b7280;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.3;
}
.scroll-arrow {
position: absolute;
width: 40px;
height: 40px;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 1;
transition: all 0.3s ease;
}
.scroll-arrow:hover {
background: rgba(255, 255, 255, 1);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.left-arrow {
left: -20px;
}
.right-arrow {
right: -20px;
}
.arrow-icon {
font-style: normal;
color: #374151;
}
/* 适配移动端 */
@media (max-width: 640px) {
.cards-grid {
grid-template-rows: 1fr; /* 在移动端切换为单行 */
}
.scroll-arrow {
display: none; /* 在移动端隐藏箭头 */
}
}
</style>