2025-07-18 15:55:39 +08:00

92 lines
2.7 KiB
Vue

<template>
<div class="animation-container" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
<img :src="spriteImage" :style="spriteStyle" alt="Animation sprite" />
</div>
</template>
<script>
export default {
name: 'SpriteAnimation',
data() {
return {
frame: 1, // 当前帧数 (1-60)
type: '外', // 动画类型 ('内'或'外')
running: false, // 是否正在执行动画
timer: null, // 动画定时器
spriteImage: 'http://192.168.0.172:5500/test1.png' // 示例base64图片
}
},
computed: {
spriteStyle() {
return {
position: 'absolute',
top: `-${(this.frame - 1) * 120}px`,
left: '0px',
width: '100%',
height: 'auto'
}
}
},
methods: {
clearAnimationTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
startAnimation() {
this.clearAnimationTimer()
this.running = true
const targetFrame = this.type === '内' ? 60 : 1
const step = this.type === '内' ? 1 : -1
const frameDuration = 2000 / 60 // 2秒完成60帧动画
this.timer = setInterval(() => {
this.frame += step
if ((step > 0 && this.frame >= targetFrame) ||
(step < 0 && this.frame <= targetFrame)) {
this.frame = targetFrame
this.clearAnimationTimer()
this.running = false
this.checkAutoReverse()
}
}, frameDuration)
},
handleMouseEnter() {
this.type = '内'
if (!this.running) this.startAnimation()
},
handleMouseLeave() {
this.type = '外'
if (!this.running) this.startAnimation()
},
checkAutoReverse() {
if (this.type === '外' && this.frame === 60) {
this.type = '内'
this.startAnimation()
} else if (this.type === '内' && this.frame === 1) {
this.type = '外'
this.startAnimation()
}
}
},
beforeUnmount() {
this.clearAnimationTimer()
}
}
</script>
<style scoped>
.animation-container {
width: 120px;
height: 120px;
position: relative;
border: 1px solid pink;
overflow: hidden;
cursor: pointer;
left: 20%;
top: 200px;
}
</style>