feat: playroom sync finished

This commit is contained in:
2026-04-04 17:48:34 +08:00
parent 970aae1c5f
commit 122971200f
4 changed files with 973 additions and 655 deletions

View File

@@ -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);