vue3.0 实现网易云音乐轮播效果

vue3.0 实现网易云音乐轮播效果

个人博客网站

  • index.vue
<!--
 * @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>

  • carsoulItem.vue
<!--
 * @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>
posted @ 2022-02-21 16:48  boyyang  阅读(269)  评论(0编辑  收藏  举报
//黑猫咪:https://unpkg.com/live2d-widget-model-hijiki@1.0.5/assets/hijiki.model.json //白猫咪:https://unpkg.com/live2d-widget-model-tororo@1.0.5/assets/tororo.model.json //萌娘:https://unpkg.com/live2d-widget-model-shizuku@1.0.5/assets/shizuku.model.json //狗狗:https://unpkg.com/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json //萌妹1号:https://unpkg.com/live2d-widget-model-z16@1.0.5/assets/z16.model.json //萌妹2号:https://unpkg.com/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json //萌妹3号:https://unpkg.com/live2d-widget-model-hibiki@1.0.5/assets/hibiki.model.json //妹子4号:https://unpkg.com/live2d-widget-model-izumi@1.0.5/assets/izumi.model.json //妹子5号:https://unpkg.com/live2d-widget-model-miku@1.0.5/assets/miku.model.json //6号:https://unpkg.com/live2d-widget-model-nico@1.0.5/assets/nico.model.json //7号:https://unpkg.com/live2d-widget-model-ni-j@1.0.5/assets/ni-j.model.json //8号:https://unpkg.com/live2d-widget-model-nipsilon@1.0.5/assets/nipsilon.model.json //9号:https://unpkg.com/live2d-widget-model-nito@1.0.5/assets/nito.model.json //10号:https://unpkg.com/live2d-widget-model-tsumiki@1.0.5/assets/tsumiki.model.json //11号:https://unpkg.com/live2d-widget-model-unitychan@1.0.5/assets/unitychan.model.json //帅哥1号:https://unpkg.com/live2d-widget-model-chitose@1.0.5/assets/chitose.model.json //帅哥2号:https://unpkg.com/live2d-widget-model-haruto@1.0.5/assets/haruto.model.json