feat: playroom sync finished
This commit is contained in:
@@ -11,6 +11,8 @@ const videoRef = ref(null);
|
||||
const player = ref(null);
|
||||
const hlsInstance = ref(null);
|
||||
|
||||
const emit = defineEmits(['canplay', 'play', 'pause', 'remote-play-failed']);
|
||||
|
||||
const props = defineProps({
|
||||
autoplay: { type: Boolean, default: false },
|
||||
videoUrl: { type: String, required: true },
|
||||
@@ -121,10 +123,12 @@ onMounted(() => {
|
||||
|
||||
player.value.on('play', () => {
|
||||
console.log('播放:', props.videoUrl);
|
||||
emit('play', { time: getCurrentTime() });
|
||||
});
|
||||
|
||||
player.value.on('pause', () => {
|
||||
console.log('暂停');
|
||||
emit('pause', { time: getCurrentTime() });
|
||||
});
|
||||
|
||||
player.value.on('ended', () => {
|
||||
@@ -140,13 +144,82 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
player.value.on('canplay', () => {
|
||||
console.log('视频可以播放');
|
||||
// 缓冲、seek 后常会多次触发;不在此刷屏打印,由父组件用 pending* 决定是否执行同步
|
||||
emit('canplay');
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('初始化播放器失败:', error);
|
||||
}
|
||||
});
|
||||
|
||||
const getCurrentTime = () => {
|
||||
const video = player.value?.video;
|
||||
if (!video || typeof video.currentTime !== 'number' || Number.isNaN(video.currentTime)) {
|
||||
return 0;
|
||||
}
|
||||
return video.currentTime;
|
||||
};
|
||||
|
||||
const seekTo = (timeSec) => {
|
||||
const t = Number(timeSec);
|
||||
if (!Number.isFinite(t) || t < 0) return;
|
||||
if (player.value?.seek) {
|
||||
try {
|
||||
player.value.seek(t);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
const video = player.value?.video;
|
||||
if (video && typeof video.currentTime === 'number') {
|
||||
try {
|
||||
video.currentTime = t;
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{ remote?: boolean }} options
|
||||
* remote=true:来自 WebSocket 同步,无用户手势;需静音才能通过多数浏览器的自动播放策略
|
||||
*/
|
||||
const play = async (options = {}) => {
|
||||
const remote = options?.remote === true;
|
||||
const video = player.value?.video;
|
||||
if (!video?.play) return false;
|
||||
if (remote) {
|
||||
try {
|
||||
video.muted = true;
|
||||
video.setAttribute?.('playsinline', 'true');
|
||||
} catch (e) {}
|
||||
}
|
||||
try {
|
||||
await video.play();
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn('[videoPlayer] play() 被拒绝(多为自动播放策略):', e?.name, e?.message);
|
||||
if (remote) {
|
||||
emit('remote-play-failed', { error: e });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const pause = () => {
|
||||
if (player.value?.pause) {
|
||||
try {
|
||||
player.value.pause();
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
const video = player.value?.video;
|
||||
if (video?.pause) {
|
||||
try {
|
||||
video.pause();
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ getCurrentTime, seekTo, play, pause });
|
||||
|
||||
watch(() => props.videoUrl, (newUrl) => {
|
||||
if (player.value && newUrl) {
|
||||
console.log('切换视频到:', newUrl);
|
||||
|
||||
Reference in New Issue
Block a user