useLiveStream.js
useLiveStream.js
:
- 该文件包含了获取直播流 URL、初始化视频播放器、销毁播放器等相关逻辑。
createVideoElement
:该函数创建一个新的视频元素并设置相关属性。initHls
:通过 HLS.js 初始化直播流,绑定到video
元素,处理直播流解析及播放。destroyHls
:销毁播放器实例,清理相关资源。
import { ref, nextTick } from 'vue';
import Hls from 'hls.js';
// 用于存储直播流信息
const liveHlsUrl = ref(null);
const isLoading = ref(false);
const isSuccess = ref(false);
let hls = null;
let videoElement = null;
// 创建视频元素
const createVideoElement = () => {
const video = document.createElement('video');
video.style.width = '100%';
video.style.aspectRatio = '16 / 9';
video.style.position = 'absolute';
video.style.top = '50%';
video.style.transform = 'translate(0, -50%)';
video.style.zIndex = '2';
video.style.objectFit = 'fill';
video.autoplay = true;
video.muted = true;
video.loop = true;
video.setAttribute('x5-video-player-type', 'h5');
video.setAttribute('x5-video-player-fullscreen', 'true');
video.setAttribute('playsinline', '');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('x5-playsinline', 'true');
return video;
};
// 初始化直播流播放器
const initHls = async (videoContainer, url) => {
await nextTick();
if (!videoContainer || !url) return;
isLoading.value = true;
// 移除所有现有的视频元素,防止重复创建
const existingVideos = videoContainer.querySelectorAll('video');
existingVideos.forEach((video) => video.remove());
// 创建新的 video 元素并插入
videoElement = createVideoElement();
videoContainer.insertBefore(videoElement, videoContainer.firstChild);
if (Hls.isSupported()) {
hls = new Hls({
debug: true,
maxBufferLength: 30,
maxMaxBufferLength: 60,
maxBufferSize: 60 * 1000 * 1000,
maxBufferHole: 0.5,
lowLatencyMode: true,
});
hls.attachMedia(videoElement);
// 当视频元素绑定成功时,加载视频源
hls.on(Hls.Events.MEDIA_ATTACHED, () => {
console.log('视频元素已绑定');
hls.loadSource(url);
});
// 直播流解析成功
hls.on(Hls.Events.MANIFEST_PARSED, () => {
console.log('直播流解析成功');
isSuccess.value = true;
isLoading.value = false;
videoElement.play().catch((err) => {
console.error('自动播放失败:', err);
});
});
// 处理错误事件
hls.on(Hls.Events.ERROR, (event, data) => {
console.error('直播流解析失败:', data);
isSuccess.value = false;
isLoading.value = false;
});
} else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
// 直接使用 `videoElement.src` 进行播放(适用于不支持 HLS.js 的浏览器)
videoElement.src = url;
}
};
// 销毁 HLS 播放器
const destroyHls = () => {
if (hls) {
hls.destroy();
hls = null;
}
if (videoElement) {
videoElement = null;
}
};
export {
liveHlsUrl,
isLoading,
isSuccess,
initHls,
destroyHls,
};
主组件
:
- 在主组件中, 获取直播流的 URL后,调用
initHls
初始化播放器。 - 在组件卸载时调用
destroyHls
清理资源。
<div ref="videoContainer" class="video-container">
<view class="cover-img">
<image :src="currentLive?.coverImg" style="width:100%;height:100%" mode="aspectFit"></image>
</view>
<view class="video-loading">
<u-loading-icon textSize="24px" v-if="isLoading" />
</view>
</div>
import { initHls, destroyHls, liveHlsUrl, isLoading, isSuccess } from './useLiveStream.js';
// 销毁播放器
onUnmounted(() => {
destroyHls();
});
initHls(videoContainer.value, liveHlsUrl.value); // 初始化播放器
使用js的好处在于 类似一个类 不需要再在js外创建很多变量了 也可以在不同的组件完成不同的展示效果