1.动画文件.vue
javascript
<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(内容显示)与动画无关
javascript
<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>