150 lines
3.6 KiB
Vue
150 lines
3.6 KiB
Vue
<!-- 使用示例 已经全局暴露直接用就行 注意!这个组件的性能不如用AE写的动画-->
|
||
<!-- <donghua :width="`1300rpx`" :height="`900rpx`" :links="blueArray" :playing="photoplay" :loop="true" :interval="120" /> -->
|
||
<!-- 注意看参数是什么意思 -->
|
||
<!-- 通用的生成函数 这个方法可以快速让你写出图片数组
|
||
function genPaths(base, prefix, count, ext = 'png', startIndex = 0, pad = false) {
|
||
return Array.from({ length: count }, (_, i) => {
|
||
const idx = pad
|
||
? String(i + startIndex).padStart(2, '0')
|
||
: i + startIndex
|
||
return `${base}/${prefix}${idx}.${ext}`
|
||
})
|
||
} -->
|
||
<!-- 数组的示例
|
||
const leftArray = ref(genPaths(
|
||
'/static/index/newindex/leftmenu',地址
|
||
'',图片前缀
|
||
3, // 一共加一起多少张图片
|
||
'png', 类型
|
||
0, // 起始索引
|
||
false // 不补零
|
||
)) -->
|
||
<template>
|
||
<view>
|
||
<image :src="isError ? defaultImage : links[currentIndex]" :style="{ width: width, height: height }"
|
||
:mode="objectFit" @error="isError = true" @load="isError = false" />
|
||
<button v-if="showButton" @click="$emit('update:playing', !playing)">
|
||
{{ playing ? '停止播放' : '开始播放' }}
|
||
</button>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
ref,
|
||
watch,
|
||
onUnmounted
|
||
} from 'vue'
|
||
|
||
// 定义组件的 props
|
||
const props = defineProps({
|
||
// links是图片地址所组成的数组
|
||
links: {
|
||
type: Array,
|
||
default: () => []
|
||
},
|
||
// 长宽的值可以传任何类型
|
||
width: {
|
||
type: String,
|
||
default: '65rpx'
|
||
},
|
||
height: {
|
||
type: String,
|
||
default: '65rpx'
|
||
},
|
||
// 展示的动画中每一帧的图片类型
|
||
objectFit: {
|
||
type: String,
|
||
default: 'aspectFill'
|
||
},
|
||
// 动画如果加载失败,展示的图片
|
||
defaultImage: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
// 注意这是每一帧图片的间隔,这个值越小加载的越快
|
||
interval: {
|
||
type: Number,
|
||
default: 80
|
||
},
|
||
// 注意,因为这是监听的机制,所以默认转态必须是false,然后在mounted这类钩子或按钮变成true来播放
|
||
playing: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 展示是否停止、开启动画的按钮
|
||
showButton: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 重要:动画时候会不停的循环
|
||
loop: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
})
|
||
|
||
// 定义组件发出的事件
|
||
const emit = defineEmits(['update:playing'])
|
||
|
||
// 组件内部状态
|
||
const currentIndex = ref(0) // 当前播放的图片索引
|
||
const isPlaying = ref(false) // 是否正在播放
|
||
const isError = ref(false) // 当前图片是否加载失败
|
||
let timer = null // 定时器
|
||
|
||
// 开始播放
|
||
const startPlay = () => {
|
||
if (isPlaying.value) return
|
||
isPlaying.value = true
|
||
timer = setInterval(() => {
|
||
if (props.loop) {
|
||
// 循环播放:使用模运算循环索引
|
||
currentIndex.value = (currentIndex.value + 1) % props.links.length
|
||
isError.value = false
|
||
} else {
|
||
// 非循环播放:到末尾时停止
|
||
if (currentIndex.value < props.links.length - 1) {
|
||
currentIndex.value++
|
||
isError.value = false
|
||
} else {
|
||
stopPlay()
|
||
}
|
||
}
|
||
}, props.interval)
|
||
}
|
||
|
||
// 停止播放
|
||
const stopPlay = () => {
|
||
isPlaying.value = false
|
||
clearInterval(timer)
|
||
}
|
||
|
||
// 监听 playing 属性变化
|
||
watch(() => props.playing, (val) => {
|
||
currentIndex.value = 0
|
||
if (val) {
|
||
startPlay()
|
||
} else {
|
||
stopPlay()
|
||
setTimeout(() => currentIndex.value = 0, 50)
|
||
|
||
}
|
||
})
|
||
|
||
// 监听 links 数组变化
|
||
watch(() => props.links, () => {
|
||
currentIndex.value = 0
|
||
isError.value = false
|
||
if (isPlaying.value) {
|
||
stopPlay()
|
||
}
|
||
}, {
|
||
deep: true
|
||
})
|
||
|
||
// 组件销毁时清理定时器
|
||
onUnmounted(() => {
|
||
stopPlay()
|
||
})
|
||
</script> |