当前位置: 首页 > article >正文

vue3 + css 列表无限循环滚动+鼠标移入停止滚动+移出继续滚动

1.动画文件.vue

<template>
    <div class="dashboard" @click="setFullScreen">
        <div class="warp-box">
            <el-scrollbar ref="scrollRef" height="100%" @scroll="handelScroll">
                <div class="animation-box" @mouseover="stopAnim" @mouseout="runAnim" v-if="arrList.length"
                    :style="{ animationDuration: animationDuration }" :class="{ stopPlay: animationStopPlay }">
                    <div class="line-item" v-for="(item, index) in arrList" :key="index">
                        <img class="item-bg" src="../../assets/images/dashboard/line-bg.png"/>
                        <div class="item-warp">
                            <div class="item-number">
                                <template v-if="index <= 2">
                                    <img :class="`icon-img img-${index}`" :src="imgArr[index]"/>
                                </template>
                                <template v-else><div class="text">{{ index }}</div></template>
                            </div>
                            <div class="item-avatar">
                                <avatarImg :avatar="item.avatar"/>
                            </div>
                            <div class="item-nickname">{{ item.nickname }}</div>
                            <div class="item-point">{{ item.point }}</div>
                        </div>
                    </div>
                    <!-- 重复一次 实现无逢滚动 -->
                    <div class="line-item" v-for="(item, index) in arrList" :key="index">
                        <img class="item-bg" src="../../assets/images/dashboard/line-bg.png"/>
                        <div class="item-warp">
                            <div class="item-number">
                                <template v-if="index <= 2">
                                    <img :class="`icon-img img-${index}`" :src="imgArr[index]"/>
                                </template>
                                <template v-else><div class="text">{{ index }}</div></template>
                            </div>
                            <div class="item-avatar">
                                <avatarImg :avatar="item.avatar"/>
                            </div>
                            <div class="item-nickname">{{ item.nickname }}</div>
                            <div class="item-point">{{ item.point }}</div>
                        </div>
                    </div>
                </div>
            </el-scrollbar>
        </div>
    </div>
</template>

<script setup>
import p0 from '../../assets/images/dashboard/icon_0.png?v=1'
import p1 from '../../assets/images/dashboard/icon_1.png?v=1'
import p2 from '../../assets/images/dashboard/icon_2.png?v=1'
import avatarImg from './avatarImg.vue'
import { nextTick, onMounted, ref, onUnmounted, reactive } from 'vue';
const animationDuration = ref(null);
const animationStopPlay = ref(false);

const imgArr = reactive([p0, p1, p2]);
const scrollRef = ref(null);
const isLoading = ref(false);
const arrList = ref([
    {
        nickname: '昵称昵称昵称昵称',
        avatar: "",
        point: 5000,
    }
]);

const search = reactive({
    page: 1, limit: 20
});
onMounted(() => {
    nextTick(() => {
        setTimeout(() => {
            setFullScreen(); //设置全屏
        }, 3000)
        //加载列表
        loadList();
    })
});

const handelScroll = (event) => {
    const wrapRef = scrollRef.value.wrapRef;
    let poor = wrapRef.scrollHeight - wrapRef.clientHeight;
    // 判断滚动到底部
    if (event.scrollTop + 20 >= poor) {
        loadList();
    }
}

const loadList = () => {
    console.log('加载更多数据...')
    if(isLoading.value) return;
    isLoading.value = true;
    for (let i = 0; i < 30; i++) {
        arrList.value.push({
            nickname: '昵称昵称昵称昵称',
            avatar: "https://pic.qqans.com/up/2024-6/17183287196520597.jpg",
            point: 5000,
        })
    }
    if (arrList.value.length <= 2) {
        animationStopPlay.value = true
        animationDuration.value = 2 + 's'//动画持续时间
    } else {
        animationStopPlay.value = false
        // 跑马灯动画
        animationDuration.value = arrList.value.length * 2 + 's'
    }
    isLoading.value = false;
}
//设置全屏
const setFullScreen = () => {
    const elem = document.getElementById('app');
    if (elem.requestFullscreen) {
        elem.requestFullscreen();
    } else if (elem.mozRequestFullScreen) { /* Firefox */
        elem.mozRequestFullScreen();
    } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
        elem.webkitRequestFullscreen();
    } else if (elem.msRequestFullscreen) { /* IE/Edge */
        elem.msRequestFullscreen();
    }
}

//鼠标移入暂停动画
const stopAnim = () => {
    animationStopPlay.value = true
}
//鼠标移除继续动画
const runAnim = () => {
    if (arrList.value.length > 2) {
        animationStopPlay.value = false
    }
}
</script>

<style lang="scss" scoped>
.dashboard {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
    background-image: url("../../assets/images/dashboard/bg-2.png");
    background-size: cover;
}
.warp-box {
    width: 46%; height: 65%;
    margin: 9.5% 0 0 36.5%;
    padding: 10px 0 10px 10px;
}
.line-item{
    width:100%; position: relative; cursor: pointer;
    font-family: XiangCuiDaZiJi35;
    .item-bg{
        width: 100%; height: auto; display: block;
    }
    .item-warp{
        width: 100%; height:100%; box-sizing: border-box; position: absolute; top: 0; left: 0;
        display: flex; justify-content: flex-start; align-items: center;
    }
}
.item-number{
    text-align: center; width: 16%; height:100%;
    color: #96795c;
    .icon-img{
        margin: 16% 0 0 28%;
        width: 60px; height: auto; display: block;
    }
    .text{
        font-size: 36px;margin: 22% 0 0 0;
    }
}
.item-avatar{
    margin-left: 3%; width: 13%; height:80%;
}
.item-nickname{
    width: 44%;
    font-size: 40px; color: #b99871;
}
.item-point{
    width: 22%;
    font-size: 28px; color: #ffffff; text-align: center;
}

.animation-box{
    animation-name: carousel;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-delay: 0s;
    animation-direction: normal;
    &.stopPlay{
        animation-play-state: paused;
    }
}
@keyframes carousel {
    0% {
        transform: translateY(0%)
    }
    100% {
        transform: translateY(-50%)
    }
}
</style>

2.组件avatarImg.vue(内容显示)与动画无关

<template>
    <div class="image-box">
        <img class="avatar-img" :src="!avatar ? avatarBg : avatar"/>
        <img class="avatar-border" src="../../assets/images/dashboard/avatar-border.png"/>
    </div>
</template>

<script setup>
import avatarBg from '../../assets/images/dashboard/avatar-bg.png?v=1'
import { defineProps } from 'vue';
defineProps({
    avatar: {
        typeof: String,
        default: () => {
            return avatarBg;
        }
    }
})
</script>

<style lang="scss" scoped>
.image-box{
    position: relative;
    .avatar-img{
        width: 80px; height: 80px; display: block;
        transform: rotate(-3deg);
        position: absolute; top: 4px; left: 3px;
    }
    .avatar-border{
        width: 90px; height: 90px; display: block;
        position: absolute; top: 0; left: 0;
    }
}
</style>


http://www.kler.cn/a/589550.html

相关文章:

  • SOC与电压的关系
  • [新能源]新能源汽车快充与慢充说明
  • GitHub Copilot 在 VS Code 上的终极中文指南:从安装到高阶玩法
  • Python学习第十九天
  • C++初阶——类和对象(四) 拷贝构造函数、赋值运算符重载函数
  • 单元测试、注解
  • EasyExcel动态拆分非固定列Excel表格
  • ZVA-Z90,罗德与施瓦茨毫米波变换器
  • 边缘端设备开发流程全解
  • uniapp-x web 开发警告提示以及解决方法
  • Rust + WebAssembly 开发环境搭建指南
  • 蓝桥杯 第五天 2021 国赛 第 5 题 最小权值
  • 使用BLSTM自动评估句子级构音障碍的可理解性
  • ssh命令
  • QVariant:Qt中万能类型的使用与理解
  • python中多重继承和泛型 作为模板让子类实现具体业务逻辑
  • Linux错误(2)程序触发SIGBUS信号分析
  • 基于Springboot+Typst的PDF生成方案,适用于报告打印/标签打印/二维码打印等
  • 开源文档管理系统 Paperless-ngx
  • 【后端开发面试题】每日 3 题(十三)