vue3.0 实现网易云音乐轮播效果
<!--
* @Author: boyyang
* @Date: 2022-02-19 16:42:09
* @LastEditTime: 2022-02-21 15:40:43
* @LastEditors: boyyang
* @Description:
* @FilePath: \boyyang\src\components\carousel\index.vue
-->
<template>
<div class="carousel-wrapper" @click="begin('click')">
<div :class="['before-item', cssArr[1]]">
<carousel-item :url="props.urls[index[0]]"></carousel-item>
</div>
<div :class="['carousel-content', cssArr[0]]">
<carousel-item :url="props.urls[index[1]]"></carousel-item>
</div>
<div :class="['after-item', cssArr[2]]">
<carousel-item :url="props.urls[index[2]]"></carousel-item>
</div>
</div>
</template>
<script lang="ts" setup>
interface ICarouselProps {
urls?: string[];
time?: number | string;
autoplay?: boolean;
height?: number;
}
interface ICarouselEmits {
(e: 'update:urls', val: string[]): void
}
const props = withDefaults(defineProps<ICarouselProps>(), {
urls: () => [],
time: 3000,
autoplay: true,
height: 400
})
const emits = defineEmits<ICarouselEmits>()
const cssArr = ref<string[]>(['after-item-leave', 'content-leave', 'before-item-leave'])
const index = ref<number[]>([0, 1, 2])
onMounted(() => {
if (props.autoplay) {
setInterval(() => {
begin('autoplay')
}, Number(props.time))
}
})
const begin = (type: string) => {
if (type == 'autoplay') {
cssArr.value.push(cssArr.value.shift() as string)
// 图片
let urls = props.urls
urls.push(urls.shift() as string)
emits('update:urls', urls)
// 下标
index.value.unshift(index.value.pop() as number)
} else {
if (!props.autoplay) {
// css
cssArr.value.push(cssArr.value.shift() as string)
// 图片
let urls = props.urls
urls.push(urls.shift() as string)
emits('update:urls', urls)
// 下标
index.value.unshift(index.value.pop() as number)
}
}
}
</script>
<style scoped lang="scss">
.carousel-wrapper {
box-sizing: border-box;
width: 100vw;
height: calc(v-bind("props.height") * 1px);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
position: relative;
margin: 10px 0;
user-select: none;
.before-item,
.after-item,
.carousel-content {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
width: 50%;
}
.before-item {
box-sizing: border-box;
height: 80%;
transform: translateX(-55%);
}
.carousel-content {
height: 100%;
}
.after-item {
box-sizing: border-box;
height: 80%;
transform: translateX(55%);
}
.before-item-leave {
transition: all 1s cubic-bezier(0.19, 1, 0.22, 1);
transform: translateX(55%);
height: 80%;
z-index: 1;
}
.content-leave {
transition: all 0.6s cubic-bezier(0.19, 1, 0.22, 1);
transform: translateX(-55%);
height: 80%;
z-index: 2;
}
.after-item-leave {
transition: all 1.5s cubic-bezier(0.19, 1, 0.22, 1);
transform: translateX(0%);
height: 100%;
z-index: 9;
}
}
</style>
<!--
* @Author: boyyang
* @Date: 2022-02-19 16:50:02
* @LastEditTime: 2022-02-20 13:30:19
* @LastEditors: boyyang
* @Description:
* @FilePath: \boyyang\src\components\carousel\carouselItem.vue
-->
<template>
<div class="carousel-item">
<div class="img">
<img :src="props.url" />
</div>
</div>
</template>
<script lang="ts" setup>
interface ICarouselItemProps {
url?: string
}
const props = withDefaults(defineProps<ICarouselItemProps>(), {})
</script>
<style scoped lang="scss">
.carousel-item {
height: 100%;
.img {
width: 100%;
height: 100%;
display: flex;
img {
height: 100%;
box-shadow: 3px 4px 5px rgba(0, 0, 0, 0.5);
border-radius: 10px;
}
}
}
</style>