arm設(shè)備蝶念,安裝的瀏覽器無法播放視頻〉5校快速播放圖片苦酱,模仿播放視頻
第一版:直接快速播放網(wǎng)絡(luò)圖片,效果非常差颂跨,1秒5幀都無法滿足
第二版:使用雙緩沖策略扯饶,網(wǎng)頁(yè)上使用兩個(gè)image標(biāo)簽輪流顯示,顯示效果有提升钓丰,但是不大
第三版:加入預(yù)加載策略每币,增加一個(gè)長(zhǎng)度為5的預(yù)加載隊(duì)列兰怠,用于預(yù)先去網(wǎng)絡(luò)請(qǐng)求圖片,每顯示一張圖片的時(shí)候肥橙,都會(huì)去更新預(yù)加載隊(duì)列秸侣,刪除最早加入的圖片,并開始預(yù)加載新的圖片方篮。效果提升明顯励负,內(nèi)網(wǎng)環(huán)境下可滿足每秒20幀的要求
優(yōu)化點(diǎn):雙緩沖+預(yù)加載
<template>
<div class="image-player">
<!-- 播放器主體區(qū)域 -->
<div class="player-container">
<img
:src="bufferA.src"
alt="播放圖片"
v-show="bufferA.isActive"
@load="handleImageLoad('A')"
:class="{ 'fade-in': bufferA.isActive }"
/>
<img
:src="bufferB.src"
alt="播放圖片"
v-show="bufferB.isActive"
@load="handleImageLoad('B')"
:class="{ 'fade-in': bufferB.isActive }"
/>
<div v-if="isLoading" class="loading-indicator">加載中...</div>
</div>
<!-- 控制按鈕區(qū)域 -->
<div class="controls">
<button @click="togglePlay">
{{ isPlaying ? "暫停" : "播放" }}
</button>
<span class="progress">
{{ currentIndex + 1 }} / {{ images.length }}
</span>
<!-- 添加幀率選擇器 -->
<div class="fps-selector">
<span>幀率:</span>
<select v-model="selectedFps">
<option v-for="fps in fpsOptions" :key="fps" :value="fps">
{{ fps }} FPS
</option>
</select>
</div>
</div>
</div>
</template>
<script>
export default {
name: "ImagePlayer",
data() {
return {
// 圖片列表數(shù)組
images: [
// 添加更多圖片URL
],
currentIndex: 0, // 當(dāng)前播放的圖片索引
isPlaying: false, // 播放狀態(tài)
playIntervalTimer: null, // 播放定時(shí)器
// 添加雙緩沖相關(guān)的數(shù)據(jù)
bufferA: {
src: "",
isActive: true,
isLoaded: false,
},
bufferB: {
src: "",
isActive: false,
isLoaded: false,
},
// 添加幀率相關(guān)數(shù)據(jù)
fpsOptions: [1, 2, 5, 10, 15, 20, 24],
selectedFps: 5, // 默認(rèn)5幀每秒
preloadQueue: [], // 預(yù)加載隊(duì)列
maxPreloadCount: 5, // 最大預(yù)加載數(shù)量
isLoading: false,
};
},
computed: {
currentImage() {
return this.images[this.currentIndex];
},
// 根據(jù)選擇的幀率計(jì)算播放間隔(毫秒)
playInterval() {
// 向下取整
return Math.floor(1000 / this.selectedFps);
},
},
created() {
// 生成100張圖片
for (let i = 0; i < 1000; i++) {
this.images.push(`https://picsum.photos/200?t=${i}`);
}
// 初始化第一張圖片
this.bufferA.src = this.images[0];
// 初始化預(yù)加載隊(duì)列
this.initPreloadQueue();
},
methods: {
// 初始化預(yù)加載隊(duì)列
initPreloadQueue() {
const startIdx = (this.currentIndex + 1) % this.images.length;
for (let i = 0; i < this.maxPreloadCount; i++) {
const idx = (startIdx + i) % this.images.length;
this.preloadImage(this.images[idx]);
}
},
// 預(yù)加載圖片
preloadImage(src) {
if (!this.preloadQueue.includes(src)) {
const img = new Image();
img.src = src;
this.preloadQueue.push(src);
if (this.preloadQueue.length > this.maxPreloadCount) {
this.preloadQueue.shift(); // 移除最早的預(yù)加載圖片
}
}
},
// 處理圖片加載
handleImageLoad(buffer) {
if (buffer === "A") {
this.bufferA.isLoaded = true;
} else {
this.bufferB.isLoaded = true;
}
this.isLoading = false;
},
// 優(yōu)化后的播放下一張圖片方法
async nextImage() {
this.isLoading = true;
const nextIndex = (this.currentIndex + 1) % this.images.length;
// 切換緩沖區(qū)
this.bufferA.isActive = !this.bufferA.isActive;
this.bufferB.isActive = !this.bufferB.isActive;
// 更新當(dāng)前索引
this.currentIndex = nextIndex;
// 預(yù)加載下一張圖片
const nextBuffer = this.bufferA.isActive ? this.bufferB : this.bufferA;
nextBuffer.isLoaded = false;
nextBuffer.src = this.images[nextIndex];
// 更新預(yù)加載隊(duì)列
const preloadIndex =
(nextIndex + this.maxPreloadCount) % this.images.length;
this.preloadImage(this.images[preloadIndex]);
},
// 優(yōu)化后的播放控制
play() {
if (!this.isPlaying) {
this.isPlaying = true;
this.playIntervalTimer = setInterval(() => {
if (!this.isLoading) {
this.nextImage();
}
}, this.playInterval);
}
},
// 切換播放/暫停狀態(tài)
togglePlay() {
if (this.isPlaying) {
this.pause();
} else {
this.play();
}
},
// 暫停播放
pause() {
this.isPlaying = false;
if (this.playIntervalTimer) {
clearInterval(this.playIntervalTimer);
this.playIntervalTimer = null;
}
},
},
// 組件銷毀時(shí)清理定時(shí)器
beforeDestroy() {
// 清理預(yù)加載隊(duì)列
this.preloadQueue = [];
this.pause();
},
// 監(jiān)聽?zhēng)首兓? watch: {
selectedFps() {
// 如果正在播放略吨,重新開始播放以應(yīng)用新的幀率
if (this.isPlaying) {
this.pause();
this.$nextTick(() => {
this.play();
});
}
},
},
};
</script>
<style scoped>
.image-player {
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.player-container {
width: 100%;
aspect-ratio: 16/9;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.player-container img {
position: absolute;
max-width: 100%;
max-height: 100%;
object-fit: contain;
will-change: transform; /* 優(yōu)化渲染性能 */
transition: opacity 0.2s ease-in-out;
}
.controls {
margin-top: 10px;
display: flex;
align-items: center;
gap: 20px; /* 增加間距 */
}
button {
padding: 8px 16px;
cursor: pointer;
}
.progress {
font-size: 14px;
}
/* 添加幀率選擇器樣式 */
.fps-selector {
display: flex;
align-items: center;
gap: 8px;
}
.fps-selector select {
padding: 4px 8px;
border-radius: 4px;
border: 1px solid #ccc;
cursor: pointer;
}
.loading-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.5);
color: white;
padding: 10px;
border-radius: 4px;
}
.fade-in {
/* animation: fadeIn 0.2s ease-in-out; */
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>