下面是详细的“Vue组件实现景深卡片轮播示例”的攻略。
什么是景深卡片轮播
景深卡片轮播是一种卡片轮播式的组件,与一般的卡片轮播不同之处在于它可以在拖动卡片时产生景深效果,即中心卡片会放大,两侧卡片会逐渐缩小。这种效果能够提升用户体验,使得轮播更加流畅自然。
如何实现景深卡片轮播
Vue组件可以很方便地实现景深卡片轮播。我们需要进行以下几个步骤:
1.组件基本结构搭建
我们需要先创建一个基本的Vue组件结构,包括template、script和style三个部分。template中需要包含卡片轮播的HTML结构,比如下面的代码:
<template>
<div class="carousel">
<div class="cards">
<div class="card" v-for="(item, index) in list" :key="index">
<img :src="item.src">
<h3>{{ item.title }}</h3>
</div>
</div>
</div>
</template>
上面的代码中,我们使用了Vue的v-for指令来循环渲染卡片,使用了:item指令来将数据绑定到每个卡片上。
2.新增组件data
我们需要在script中新增一个data属性,用于存储组件内的数据。具体来说,我们需要存储卡片列表和当前活跃的卡片编号,如下所示:
<script>
export default {
data() {
return {
list: [ /* ... */ ], // 卡片列表
activeIndex: 0 // 当前活跃的卡片编号
}
}
}
</script>
3.编写拖动事件逻辑
接下来,我们需要编写拖动事件的逻辑,在用户拖动卡片时,计算出当前拖动距离,并据此确定卡片的缩放比例和位置变化。具体步骤如下:
3.1监听鼠标/触摸事件
首先,我们需要监听用户的鼠标/触摸事件,获取拖动的距离。最简单的方式是使用Vue的@mousedown/@touchstart、@mousemove/@touchmove和@mouseup/@touchend事件,具体代码如下:
<template>
<div class="carousel"
@mousedown="onDragStart"
@touchstart="onDragStart"
@mousemove="onDragMove"
@touchmove="onDragMove"
@mouseup="onDragEnd"
@touchend="onDragEnd"
>
<!-- 省略卡片结构代码 -->
</div>
</template>
3.2计算拖动距离
当用户按下鼠标或触摸屏幕时,我们需要记录下此时的鼠标/触摸点的坐标,以后每次移动时计算出距离:
<script>
export default {
// 省略其它代码...
methods: {
onDragStart(event) {
this.startPos = event.clientX || event.touches[0].clientX
},
onDragMove(event) {
if (!this.startPos) return
const currentPos = event.clientX || event.touches[0].clientX
this.dist = currentPos - this.startPos
},
onDragEnd() {
this.startPos = null
this.dist = 0
}
}
}
</script>
3.3计算缩放比例和位置变化
有了拖动距离之后,我们就需要根据该距离计算出每张卡片的缩放比例和位置变化了。这里我们可以使用CSS3的transform属性。下面是一个示例CSS,用于将卡片按照x轴平移:
.card {
position: relative;
transform: translateX(0);
}
我们需要在此基础上增加缩放比例和z-index属性,实现景深效果:
.card.active {
z-index: 1; /* 将当前卡片置于最上层 */
transform: translateX(0) scale(1.2); /* 放大当前卡片 */
}
.card.prev {
z-index: 0;
transform: translateX(calc(-100% + var(--gap))) scale(1);
}
.card.next {
z-index: 0;
transform: translateX(calc(100% - var(--gap))) scale(1);
}
在计算出拖动距离后,我们需要将每张卡片的样式进行调整。具体来说,我们需要在当前活跃卡片的基础上,将左侧和右侧的卡片进行平移和缩放。具体代码如下:
<script>
export default {
// 省略其它代码...
methods: {
onDragMove(event) {
// 省略获取拖动距离的代码...
const delta = this.dist / window.innerWidth
this.list.forEach((card, index) => {
const distance = index - this.activeIndex + delta
const absDistance = Math.abs(distance)
if (absDistance > 1) {
// 卡片距离太大,直接隐藏
card.hidden = true
} else {
// 重新计算card的位置和大小
card.hidden = false
const scale = absDistance < 0.5 ? 1.2 - absDistance * 1.2 : 1
const zIndex = absDistance < 0.5 ? 1 : 0
const x = Math.min(Math.max(distance, -1), 1) * 100
card.style.transform = `translateX(${x.toFixed(2)}%) scale(${scale.toFixed(2)})`
card.style.zIndex = zIndex
card.classList.remove('active', 'prev', 'next')
if (distance < 0) {
card.classList.add('prev')
} else if (distance > 0) {
card.classList.add('next')
} else {
card.classList.add('active')
}
}
})
},
}
}
</script>
上面的代码中,我们使用了forEach循环遍历每个卡片,计算出它们的位置和缩放比例。然后将对应的CSS样式应用到卡片上。
4.完整代码
组件结构和完整代码如下所示:
<template>
<div class="carousel"
@mousedown="onDragStart"
@touchstart="onDragStart"
@mousemove="onDragMove"
@touchmove="onDragMove"
@mouseup="onDragEnd"
@touchend="onDragEnd"
>
<div class="cards">
<div class="card"
v-for="(item, index) in list"
:key="index"
:class="{ active: activeIndex === index }"
:style="{ backgroundImage: `url(${item.src})` }"
>
<h3>{{ item.title }}</h3>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeIndex: 0,
startPos: null,
dist: 0,
list: [
{ title: 'Card 1', src: 'https://picsum.photos/300?random=1' },
{ title: 'Card 2', src: 'https://picsum.photos/300?random=2' },
{ title: 'Card 3', src: 'https://picsum.photos/300?random=3' },
{ title: 'Card 4', src: 'https://picsum.photos/300?random=4' },
{ title: 'Card 5', src: 'https://picsum.photos/300?random=5' },
]
}
},
methods: {
onDragStart(event) {
this.startPos = event.clientX || event.touches[0].clientX
},
onDragMove(event) {
if (!this.startPos) return
const currentPos = event.clientX || event.touches[0].clientX
this.dist = currentPos - this.startPos
const delta = this.dist / window.innerWidth
this.list.forEach((card, index) => {
const distance = index - this.activeIndex + delta
const absDistance = Math.abs(distance)
if (absDistance > 1) {
card.hidden = true
} else {
card.hidden = false
const scale = absDistance < 0.5 ? 1.2 - absDistance * 1.2 : 1
const zIndex = absDistance < 0.5 ? 1 : 0
const x = Math.min(Math.max(distance, -1), 1) * 100
card.style.transform = `translateX(${x.toFixed(2)}%) scale(${scale.toFixed(2)})`
card.style.zIndex = zIndex
card.classList.remove('active', 'prev', 'next')
if (distance < 0) {
card.classList.add('prev')
} else if (distance > 0) {
card.classList.add('next')
} else {
card.classList.add('active')
}
}
})
},
onDragEnd() {
if (Math.abs(this.dist / window.innerWidth) > 0.2) {
this.activeIndex += this.dist > 0 ? -1 : 1
}
this.startPos = null
this.dist = 0
}
}
}
</script>
<style scoped>
.carousel {
overflow: hidden;
position: relative;
}
.card {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border-radius: 5px;
background-size: cover;
background-position: center;
position: absolute;
top: 10px;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: 80%;
height: calc(100% - 20px);
transition: transform 0.3s ease-in-out, opacity 0.2s ease-in-out, z-index 0.2s ease-in-out;
opacity: 1;
}
.card.active {
z-index: 1;
transform: translateX(0) scale(1.2);
}
.card.prev {
z-index: 0;
transform: translateX(calc(-100% + var(--gap))) scale(1);
}
.card.next {
z-index: 0;
transform: translateX(calc(100% - var(--gap))) scale(1);
}
h3 {
position: absolute;
bottom: 10px;
left: 10px;
font-size: 24px;
font-weight: normal;
margin: 0;
color: #fff;
text-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
}
@media (min-width: 768px) {
.cards {
display: flex;
flex-wrap: nowrap;
overflow-x: hidden;
gap: var(--gap);
padding: 0 var(--gap);
position: relative;
}
.card {
width: 40%;
height: auto;
transform-origin: center center;
opacity: 0.8;
}
}
</style>
示例一
下面是一个使用景深卡片轮播的简单示例:
<template>
<div class="container">
<h1>景深卡片轮播示例</h1>
<carousel />
</div>
</template>
<script>
import Carousel from './Carousel.vue'
export default {
components: {
Carousel
},
}
</script>
<style>
.container {
max-width: 768px;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
font-family: sans-serif;
text-align: center;
}
</style>
上面的代码中,我们引用了另一个文件中的Carousel组件,并使用它来展示一组图片。
示例二
下面是一个稍微复杂一些的使用景深卡片轮播的示例:
<template>
<div class="container">
<h1>景深卡片轮播示例</h1>
<carousel :list="items" />
</div>
</template>
<script>
import Carousel from './Carousel.vue'
export default {
components: {
Carousel
},
data() {
return {
items: [
{ title: 'Card 1', src: 'https://cdn.pixabay.com/photo/2021/03/22/20/59/deer-6114771_960_720.jpg' },
{ title: 'Card 2', src: 'https://cdn.pixabay.com/photo/2021/03/18/12/15/horse-6103053_960_720.jpg' },
{ title: 'Card 3', src: 'https://cdn.pixabay.com/photo/2021/03/03/06/13/cat-6069625_960_720.jpg' },
{ title: 'Card 4', src: 'https://cdn.pixabay.com/photo/2020/02/27/11/02/squirrel-4888356_960_720.jpg' },
{ title: 'Card 5', src: 'https://cdn.pixabay.com/photo/2021/01/23/08/28/road-5933362_960_720.jpg' },
{ title: 'Card 6', src: 'https://cdn.pixabay.com/photo/2021/03/19/14/58/spring-6106911_960_720.jpg' },
{ title: 'Card 7', src: 'https://cdn.pixabay.com/photo/2016/12/13/05/15/puppy-1903313_960_720.jpg' },
{ title: 'Card 8', src: 'https://cdn.pixabay.com/photo/2021/03/22/10/40/flowers-6113829_960_720.jpg' },
{ title: 'Card 9', src: 'https://cdn.pixabay.com/photo/2016/01/14/18/54/piano-1149029_960_720.jpg' },
]
}
}
}
</script>
<style>
.container {
max-width: 768px;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
font-family: sans-serif;
text-align: center;
}
</style>
上面的代码中,我们自己生成了一组图片,并将它们设置为Carousel组件的属性,从而展示一组美丽的图片。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue组件实现景深卡片轮播示例 - Python技术站