“UniApp的音频播放——点击视频进入空白+解决视频播放器切换视频时一直加载的问题”——video.js、video-js.css
今天,又解决了一个单子“UniApp的音频播放——点击视频进入空白+解决视频播放器切换视频时一直加载的问题”
一、问题描述
在开发一个基于 video.js
的视频播放器时,用户通过上下滑动切换视频时,视频一直处于加载状态,无法正常播放。通过日志可以看到,视频源地址和索引更新是正确的,但视频无法播放。具体表现为:
-
视频加载卡住:切换视频时,播放器一直显示加载动画,无法播放视频。
-
日志显示正常:日志中显示的视频源地址和索引更新是正确的,例如:
即将更新视频源为: http://127.0.0.1:8000/media/m3u8/30bd5d2225919b1724ca69d07633beb1/index.m3u8 currentIndex: 1 videos长度: 4
-
播放器未正确响应:尽管视频源地址更新了,但播放器未能正确加载和播放新视频。
二、问题复现步骤
-
初始化播放器:加载第一个视频,播放器正常工作。
-
滑动切换视频:用户通过上下滑动切换到下一个视频。
-
视频加载卡住:播放器显示加载动画,但视频无法播放。
-
日志输出:日志显示视频源地址和索引更新正确,但播放器未响应。
三、来请看代码,各位客官
<template>
<!-- <view
@click="handleVideoClick"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
> -->
<!-- 根据 isAdVideo 的值决定显示广告视频还是常规视频 -->
<!-- 对于广告视频,不显示控制条,自动播放 -->
<!-- <video v-if="isAdVideo" :src="videoSrc" :controls="false" autoplay></video> -->
<!-- 对于常规视频,显示控制条,自动播放 -->
<!-- <video v-else :src="videoSrc" controls autoplay></video> -->
<!-- </view> -->
<view>
<div id="app">
<div class="video-js" ref="videos"></div>
</div>
</view>
</template>
<script>
import { baseUrl } from '@/common/api.js'
export default {
data() {
return {
// 存储当前视频文件的路径
videoSrc: '',
// 标记当前视频是否为广告视频
isAdVideo: false,
// 存储广告的 URL
adUrl: '',
// 存储当前视频在视频列表中的索引
currentIndex: 0,
// 存储所有视频的数组
videos: [],
// 存储触摸开始时的 Y 坐标
touchStartY: 0,
// 存储触摸结束时的 Y 坐标
touchEndY: 0,
// video.js 的播放器实例
player: null,
};
},
onLoad(options) {
// 从传入的参数中获取视频文件路径
const videoFile = options.videoFile;
// 判断是否为广告视频,将字符串 'true' 转换为布尔值
const isAd = options.isAd === 'true';
// 从传入的参数中获取广告 URL,并进行解码
const adUrl = options.adUrl? decodeURIComponent(options.adUrl) : '';
// 从传入的参数中获取视频列表,并将其从 JSON 字符串转换为数组
const videos = options.videos? JSON.parse(decodeURIComponent(options.videos)) : [];
// 将视频文件路径存储到 data 中,修改错误点 1
// this.videoFile = videoFile;
// 将是否为广告视频的状态存储到 data 中
this.isAdVideo = isAd;
// 将广告 URL 存储到 data 中
this.adUrl = adUrl;
// 将视频列表存储到 data 中
this.videos = videos;
// 根据是否为广告视频来确定视频源的路径
if (isAd) {
// 假设广告视频的文件名直接作为参数传递,提取文件名
const adVideoPath = `${videoFile}`;
console.log('1111',adVideoPath);
// 拼接完整的广告视频源路径
this.videoSrc = `${baseUrl}${adVideoPath}`;
} else {
// 对于常规视频,在视频列表中查找匹配的视频文件
const video = videos.find(v => {
console.log('当前视频的 m3u8_url:', v.m3u8_url); // 打印每个视频的 m3u8_url
return v.m3u8_url === videoFile;
});
console.log('222',videoFile);
// const video = videos.find(v => v.m3u8_url === videoFile);
// console.log('222',v =>v.m3u8_url,videoFile);
if (video) {
// 拼接完整的常规视频源路径
this.videoSrc = `${baseUrl}${video.m3u8_url}`;
} else {
// 如果未找到对应的视频文件,打印错误信息并退出方法
console.error('未找到对应的视频文件路径');
return;
}
}
// 查找当前视频在视频列表中的索引
this.currentIndex = this.videos.findIndex(v => {
if (this.isAdVideo) {
const asa =v.ad && v.ad.m3u8_url === videoFile;
// 对于广告视频,通过广告视频文件查找索引
console.log('当前视频的 vad:', v.ad.m3u8_url,asa);
console.log('videoFile',videoFile)
return asa ;
}
// 对于常规视频,通过常规视频文件查找索引
return v.m3u8_url === videoFile;
});
console.log('this.videoFile',videos.find(v => v.m3u8_url === videoFile).m3u8_url);
// 打印初始的视频文件路径
console.log('Initial video file:', this.videoSrc);
},
// beforeDestroy() {
// var playerElement = document.getElementById('video');
// var player = videojs.getInstance(playerElement);
// if (player) {
// player.dispose();
// }
// },
mounted() {
this.initplayer();
},
beforeDestroy() {
// 使用 $refs 来查找 video 元素
const videoElement = this.$refs.videos.querySelector('video');
if (videoElement) {
const player = videojs.getPlayer(videoElement);
if (player) {
console.log('播放器正在销毁');
player.dispose();
} else {
console.log('未找到播放器实例,可能未初始化');
}
} else {
console.log('未找到 video 元素');
}
},
methods: {
initplayer(){
// const videoElement = this.$refs.videos.querySelector('video');
// const player = videojs.getPlayer(videoElement);
// player.dispose();
// if (this.player) {
// // 如果播放器已经初始化,直接设置新的视频源
// this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' });
// this.player.play();
// return;
// }
let video = document.createElement('video');
video.id = 'video';
// video.style = 'width: 100%; height: 100%;';
// video.controls = true;
video.preload = "auto"
video.setAttribute('playsinline', true) //IOS微信浏览器支持小窗内播放
video.setAttribute('webkit-playsinline', true) //这个bai属性是ios 10中设置可以让视频在小du窗内播放,也就是不是全zhi屏播放的video标签的一个属性
video.setAttribute('x5-video-player-type', 'h5') //安卓 声明启用同层H5播放器 可以在video上面加东西
// const ada='http://127.0.0.1:8000/media\\m3u8\\caba10d1b61e5f2aa1e068bebeb55663\\index.m3u8';
let source = document.createElement('source');
// source.src = ada;
source.src = this.videoSrc;
video.appendChild(source);
// return
this.$refs.videos.appendChild(video);
let that = this;
let player = this.$video(
'video',
{
autoDisable: true,
preload: 'none', //auto - 当页面加载后载入整个视频 meta - 当页面加载后只载入元数据 none - 当页面加载后不载入视频
language: 'zh-CN',
fluid: true, // 自适应宽高
muted: false, // 是否静音
aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
controls: true, //是否拥有控制条 【默认true】,如果设为false ,那么只能通过api进行控制了。也就是说界面上不会出现任何控制按钮
autoplay: false, //如果true,浏览器准备好时开始回放。 autoplay: "muted", // //自动播放属性,muted:静音播放
loop: true, // 导致视频一结束就重新开始。 视频播放结束后,是否循环播放
controlBar: {
volumePanel: { //声音样式
inline: true // 不使用水平方式
},
timeDivider: true, // 时间分割线
durationDisplay: true, // 总时间
progressControl: true, // 进度条
remainingTimeDisplay: true, //当前以播放时间
fullscreenToggle: true, //全屏按钮
pictureInPictureToggle: false, //画中画
}
},
function() {
this.on('error', function(err) { //请求数据时遇到错误
console.log("请求数据时遇到错误", err)
});
this.on('stalled', function(stalled) { //网速失速
console.log("网速失速", stalled)
});
});
},
// 处理触摸开始事件,记录触摸开始时的 Y 坐标
handleTouchStart(event) {
this.touchStartY = event.touches[0].clientY;
},
// 处理触摸移动事件,目前不做任何处理,可添加优化逻辑
handleTouchMove(event) {
// 例如,可以添加代码防止快速滑动时的抖动效果
},
// 处理触摸结束事件,记录触摸结束时的 Y 坐标,并调用 handleSwipe 方法
handleTouchEnd(event) {
this.touchEndY = event.changedTouches[0].clientY;
this.handleSwipe();
},
// 处理滑动操作
handleSwipe() {
// 计算触摸的垂直距离
const distance = this.touchEndY - this.touchStartY;
// 如果滑动距离小于 30 像素,不进行任何操作
if (Math.abs(distance) < 30) {
return;
}
// 如果滑动距离大于 0,表示向下滑动,调用 handleSwipeDown 方法
if (distance > 0) {
this.handleSwipeDown();
} else {
// 否则表示向上滑动,调用 handleSwipeUp 方法
this.handleSwipeUp();
}
},
// 处理向上滑动,切换到下一个视频
handleSwipeUp() {
// 如果不是最后一个视频
if (this.currentIndex < this.videos.length - 1) {
// 增加当前视频索引
this.currentIndex++;
// 更新视频信息
this.updateVideo();
// 打印下一个视频的文件路径
console.log('Swipe Up: Next video file:', this.videoSrc);
// 打印是否为广告视频
console.log('是否广告', this.isAdVideo);
} else {
// 已到达最后一个视频,打印提示信息
console.log("已经是最后一个视频了");
}
},
// 处理向下滑动,切换到上一个视频
handleSwipeDown() {
// 如果不是第一个视频
if (this.currentIndex > 0) {
// 减小当前视频索引
this.currentIndex--;
// 更新视频信息
this.updateVideo();
// 打印上一个视频的文件路径
console.log('Swipe Down: Previous video file:', this.videoSrc);
} else {
// 已到达第一个视频,打印提示信息
console.log("已经是第一个视频了");
}
},
// 更新视频信息,包括视频源和广告 URL
updateVideo() {
// 获取当前索引对应的下一个视频
const nextVideo = this.videos[this.currentIndex];
console.log('11111', this.videos, nextVideo, this.currentIndex);
// 判断下一个视频是否为广告视频
this.isAdVideo =!!nextVideo.ad;
if (this.isAdVideo) {
// 如果是广告视频,更新视频源为广告视频源并打印
console.log('1111:', nextVideo.ad.m3u8_url);
this.videoSrc = `${baseUrl}${nextVideo.ad.m3u8_url}`;
} else {
// 如果是常规视频,更新视频源为常规视频源并打印
this.videoSrc = `${baseUrl}${nextVideo.m3u8_url}`;
console.log('2222:', nextVideo.m3u8_url);
}
// 根据是否为广告视频更新广告 URL,修改错误点 3
if (this.isAdVideo) {
this.adUrl = nextVideo.ad.urll;
} else {
this.adUrl = '';
}
// 当视频源更新时,更新播放器的 src
if (this.player) {
this.player.src({ src: this.videoSrc });}
},
// 处理视频点击事件
handleVideoClick() {
// 如果是广告视频且有广告 URL
if (this.isAdVideo && this.adUrl) {
// 根据不同的平台,使用不同的跳转方式打开广告 URL
if (process.env.VUE_APP_PLATFORM === 'h5') {
// 在 H5 平台使用 window.open 打开广告 URL
window.open(this.adUrl, '_blank');
} else {
// 在小程序或其他平台使用 uni.navigateTo 进行跳转
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(this.adUrl)}`
});
}
}
}
}
};
</script>
三、可能的原因
-
视频源路径格式问题:
-
视频路径中使用了反斜杠
\
,例如:http://127.0.0.1:8000\media\m3u8\30bd5d2225919b1724ca69d07633beb1\index.m3u8
。 -
反斜杠在某些环境下可能导致路径解析错误。
-
-
播放器未正确销毁和重新初始化:
-
在切换视频时,旧的播放器实例可能未正确销毁,导致新的播放器实例无法正常初始化。
-
-
视频加载超时或失败:
-
视频文件可能无法加载,或者加载时间过长,导致播放器一直处于加载状态。
-
-
用户交互限制:
-
某些浏览器要求视频播放必须在用户交互后触发,如果未正确处理用户交互,可能导致视频无法播放。
-
-
播放器初始化问题:
-
播放器初始化逻辑中,
this.$video
未定义,可能导致播放器无法正确初始化。
-
-
广告视频逻辑问题:
-
广告视频的逻辑中,
nextVideo.ad.urll
拼写错误,导致广告 URL 无法正确更新。
-
四、问题分析
1. 视频路径格式问题
-
问题:视频路径中使用了反斜杠
\
,例如:http://127.0.0.1:8000\media\m3u8\30bd5d2225919b1724ca69d07633beb1\index.m3u8
。 -
影响:在某些环境下,反斜杠可能导致路径解析错误,视频无法加载。
-
解决方案:将反斜杠替换为正斜杠
/
。
this.videoSrc = `${baseUrl}${videoFile}`.replace(/\\/g, '/');
2. 播放器未正确销毁和重新初始化
-
问题:在切换视频时,旧的播放器实例可能未正确销毁,导致新的播放器实例无法正常初始化。
-
影响:切换视频时,播放器可能卡在加载状态或无法播放。
-
解决方案:在切换视频时,销毁旧的播放器实例并重新初始化新的播放器实例。
updateVideo() {
const nextVideo = this.videos[this.currentIndex];
this.isAdVideo = !!nextVideo.ad;
if (this.isAdVideo) {
this.videoSrc = `${baseUrl}${nextVideo.ad.m3u8_url}`.replace(/\\/g, '/');
} else {
this.videoSrc = `${baseUrl}${nextVideo.m3u8_url}`.replace(/\\/g, '/');
}
this.adUrl = this.isAdVideo ? nextVideo.ad.url : '';
console.log('即将更新视频源为:', this.videoSrc);
this.destroyPlayer(); // 销毁旧的播放器实例
this.$nextTick(() => {
this.initplayer(); // 重新初始化播放器
});
}
3. 视频加载超时或失败
-
问题:视频文件可能无法加载,或者加载时间过长,导致播放器一直处于加载状态。
-
影响:用户可能会看到视频一直加载,无法播放。
-
解决方案:设置超时机制,防止长时间停留在加载状态。
async updateVideoSource() { if (!this.player) return; console.log('正在更新视频源:', this.videoSrc); try { this.player.pause(); // 暂停当前播放 this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' }); this.player.load(); // 监听 loadeddata 事件,确保视频数据加载完成后再尝试播放 this.player.one('loadeddata', () => { console.log('视频数据加载完成'); this.isPlaying = false; this.player.play().then(() => { this.isPlaying = true; }).catch(error => { console.error('播放失败:', error); }); }); // 设置一个超时机制,防止长时间停留在加载状态 const timeoutId = setTimeout(() => { console.warn('视频加载超时'); // 尝试重新加载视频 this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' }); this.player.load(); }, 10000); // 10秒超时 // 当视频加载完成时清除超时 this.player.on('loadeddata', () => clearTimeout(timeoutId)); } catch (error) { console.error('更新视频源并准备播放失败:', error); } }
4. 用户交互限制
-
问题:某些浏览器要求视频播放必须在用户交互后触发,如果未正确处理用户交互,可能导致视频无法播放。
-
影响:视频无法自动播放,用户需要手动点击播放按钮。
-
解决方案:在用户交互后触发视频播放。
handleTouchEnd(event) {
this.touchEndY = event.changedTouches[0].clientY;
this.handleSwipe();
this.isUserInteracted = true; // 标记用户交互
if (this.player && this.isUserInteracted) {
this.player.play().catch(error => {
console.error('播放失败:', error);
});
}
}
5. 播放器初始化问题
-
问题:播放器初始化逻辑中,
this.$video
未定义,可能导致播放器无法正确初始化。 -
影响:播放器无法正常工作。
-
解决方案:使用
videojs
直接初始化播放器。initplayer() { let video = document.createElement('video'); video.id = 'video'; video.preload = "auto"; video.setAttribute('playsinline', true); video.setAttribute('webkit-playsinline', true); video.setAttribute('x5-video-player-type', 'h5'); let source = document.createElement('source'); source.src = this.videoSrc; video.appendChild(source); this.$refs.videos.appendChild(video); this.player = videojs(video, { autoplay: false, controls: !this.isAdVideo, sources: [{ src: this.videoSrc, type: 'application/x-mpegURL' }] }); this.player.on('error', (error) => { console.error('视频加载错误:', error); }); }
6. 播放器销毁问题
-
问题:在
beforeDestroy
钩子中,播放器销毁逻辑可能无法正确执行。 -
影响:播放器实例可能未正确销毁,导致内存泄漏。
-
解决方案:确保播放器实例被正确销毁。
beforeDestroy() { if (this.player) { console.log('播放器正在销毁'); this.player.dispose(); this.player = null; } else { console.log('未找到播放器实例,可能未初始化'); } }
7. 日志输出不足
-
问题:日志输出较少,难以定位问题。
-
影响:调试困难。
-
解决方案:在关键步骤添加日志输出。
console.log('即将更新视频源为:', this.videoSrc); console.log('currentIndex:', this.currentIndex); console.log('videos长度:', this.videos.length);
8. 广告视频逻辑问题
-
问题:广告视频的逻辑中,
nextVideo.ad.urll
拼写错误。 -
影响:广告 URL 无法正确更新。
-
解决方案:修正拼写错误。
if (this.isAdVideo) { this.adUrl = nextVideo.ad.url; // 修正拼写错误 } else { this.adUrl = ''; }
-
五、完整代码
-
<template> <view @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"> <!-- 视频容器 --> <div id="app"> <div class="video-js" ref="videos"></div> </div> </view> </template> <script> import { baseUrl } from '@/common/api.js'; import videojs from 'video.js'; import 'video.js/dist/video-js.css'; // 引入默认样式 export default { name: 'VideoPlayer', data() { return { videoSrc: '', isAdVideo: false, adUrl: '', currentIndex: 0, videos: [], touchStartY: 0, touchEndY: 0, player: null, // video.js 的播放器实例 uniqueKey: Date.now(), // 用于强制刷新组件 isPlaying: false, // 跟踪播放状态 isUserInteracted: false, // 跟踪用户交互状态 }; }, onLoad(options) { this.initFromOptions(options); }, activated() { // 当组件被激活时(从缓存中恢复),重新初始化播放器 this.$nextTick(() => this.initplayer()); }, deactivated() { // 当组件被停用时(进入缓存),销毁播放器 this.destroyPlayer(); }, mounted() { // 确保在挂载时初始化播放器 this.$nextTick(() => this.initplayer()); }, methods: { async initFromOptions(options) { const videoFile = options.videoFile; const isAd = options.isAd === 'true'; const adUrl = options.adUrl ? decodeURIComponent(options.adUrl) : ''; const videos = options.videos ? JSON.parse(decodeURIComponent(options.videos)) : []; this.isAdVideo = isAd; this.adUrl = adUrl; this.videos = videos; if (isAd) { this.videoSrc = `${baseUrl}${videoFile}`.replace(/\\/g, '/'); } else { const video = videos.find(v => v.m3u8_url === videoFile); if (video) { this.videoSrc = `${baseUrl}${video.m3u8_url}`.replace(/\\/g, '/'); } else { console.error('未找到对应的视频文件路径'); return; } } this.currentIndex = this.videos.findIndex(v => { if (this.isAdVideo) { return v.ad && v.ad.m3u8_url === videoFile; } return v.m3u8_url === videoFile; }); console.log('Initial video file:', this.videoSrc); await this.initplayer(); // 确保播放器初始化完成 }, async initplayer() { // 如果播放器已经存在,则更新源而不是重新创建 if (this.player) { await this.updateVideoSource(); return; } let videoElement = document.createElement('video'); videoElement.id = 'video'; videoElement.preload = "auto"; videoElement.setAttribute('playsinline', true); videoElement.setAttribute('webkit-playsinline', true); videoElement.setAttribute('x5-video-player-type', 'h5'); let source = document.createElement('source'); source.src = this.videoSrc; videoElement.appendChild(source); this.$refs.videos.appendChild(videoElement); // 使用 Vue 的 nextTick 方法确保 DOM 更新完成后才初始化 Video.js 播放器 this.$nextTick(() => { this.player = videojs( videoElement, { autoplay: false, controls: !this.isAdVideo, sources: [{ src: this.videoSrc, type: 'application/x-mpegURL' }] }, async function onPlayerReady() { console.log("播放器已准备好"); try { if (this.isUserInteracted) { await this.play(); // 使用 async/await 确保 play() 完成 } } catch (error) { console.error('播放失败:', error); } }.bind(this) ); // 监听错误事件 this.player.on('error', (error) => { console.error('视频加载错误:', error); console.error('错误详情:', this.player.error()); // 获取详细的错误信息 }); }); }, destroyPlayer() { if (this.player) { console.log('播放器正在销毁'); this.player.dispose(); this.player = null; // 清除 player 实例引用 } else { console.log('未找到播放器实例,可能未初始化'); } }, async updateVideoSource() { if (!this.player) return; console.log('正在更新视频源:', this.videoSrc); try { this.player.pause(); // 暂停当前播放 this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' }); this.player.load(); // 监听 loadeddata 事件,确保视频数据加载完成后再尝试播放 this.player.one('loadeddata', () => { console.log('视频数据加载完成'); this.isPlaying = false; this.player.play().then(() => { this.isPlaying = true; }).catch(error => { console.error('播放失败:', error); // 可以在这里添加重试逻辑或提示用户 }); }); // 设置一个超时机制,防止长时间停留在加载状态 const timeoutId = setTimeout(() => { console.warn('视频加载超时'); // 尝试重新加载视频 this.player.src({ src: this.videoSrc, type: 'application/x-mpegURL' }); this.player.load(); }, 10000); // 10秒超时 // 当视频加载完成时清除超时 this.player.on('loadeddata', () => clearTimeout(timeoutId)); } catch (error) { console.error('更新视频源并准备播放失败:', error); // 可以在这里添加重试逻辑或提示用户 } }, handleTouchStart(event) { this.touchStartY = event.touches[0].clientY; }, handleTouchMove(event) { // 这里可以添加优化逻辑,但目前保持原样 }, handleTouchEnd(event) { this.touchEndY = event.changedTouches[0].clientY; this.handleSwipe(); this.isUserInteracted = true; // 标记用户交互 if (this.player && this.isUserInteracted) { this.player.play().catch(error => { console.error('播放失败:', error); }); } }, handleSwipe() { const distance = this.touchEndY - this.touchStartY; if (Math.abs(distance) < 30) return; if (distance > 0) { this.handleSwipeDown(); } else { this.handleSwipeUp(); } }, handleSwipeUp() { if (this.currentIndex < this.videos.length - 1) { this.currentIndex++; this.updateVideo(); console.log('Swipe Up: Next video file:', this.videoSrc); console.log('是否广告', this.isAdVideo); } else { console.log("已经是最后一个视频了"); } }, handleSwipeDown() { if (this.currentIndex > 0) { this.currentIndex--; this.updateVideo(); console.log('Swipe Down: Previous video file:', this.videoSrc); } else { console.log("已经是第一个视频了"); } }, updateVideo() { const nextVideo = this.videos[this.currentIndex]; this.isAdVideo = !!nextVideo.ad; if (this.isAdVideo) { this.videoSrc = `${baseUrl}${nextVideo.ad.m3u8_url}`.replace(/\\/g, '/'); } else { this.videoSrc = `${baseUrl}${nextVideo.m3u8_url}`.replace(/\\/g, '/'); } this.adUrl = this.isAdVideo ? nextVideo.ad.url : ''; console.log('即将更新视频源为:', this.videoSrc); // 添加日志输出 console.log('currentIndex:', this.currentIndex); // 添加日志输出 console.log('videos长度:', this.videos.length); // 添加日志输出 this.destroyPlayer(); // 销毁旧的播放器实例 this.$nextTick(() => { this.initplayer(); // 重新初始化播放器 }); }, handleVideoClick() { if (this.isAdVideo && this.adUrl) { if (process.env.VUE_APP_PLATFORM === 'h5') { window.open(this.adUrl, '_blank'); } else { uni.navigateTo({ url: `/pages/webview/webview?url=${encodeURIComponent(this.adUrl)}` }); } } } }, watch: { // 监听路由变化并强制刷新组件 $route(to, from) { this.uniqueKey = Date.now(); // 改变 key 来强制刷新组件 this.$nextTick(() => this.initplayer()); // 确保播放器在路由变化后重新初始化 } } }; </script> <style scoped> /* 添加样式 */ #app { width: 100%; height: 100%; } .video-js { width: 100%; height: 100%; } </style>
-
总结
通过修复视频路径格式、确保播放器正确销毁和重新初始化、处理视频加载超时、确保用户交互后播放、修正播放器初始化逻辑以及修正广告视频逻辑,可以有效解决视频切换时一直加载的问题。如果问题仍然存在,建议进一步检查视频源的有效性和网络状态,并使用浏览器的开发者工具查看网络请求和错误日志。
原文地址:https://blog.csdn.net/2301_81807150/article/details/145192806
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!