Vue3使用vue3-youtube双实例遇YT未定义错误及响应式切换问题
问题分析与解决方案
错误原因
你用display:none切换两个YouTube组件时,组件并没有被销毁,只是视觉上被隐藏,两个<YouTube>实例都会尝试初始化YouTube IFrame API。这会引发两个核心问题:
- 重复注入API脚本,导致加载冲突
- 其中一个组件初始化时,API可能还未加载完成,直接抛出
YT is not defined的错误
另外你重复绑定了两次resize监听,宽度判断的边界值(590/591)也会导致切换时出现不必要的闪烁,需要同步优化。
替代方案
方案1:用v-if替代类绑定(推荐)
v-if会在条件不满足时直接销毁组件,满足条件时才重新挂载,这样同一时间只有一个YouTube组件存在,从根源避免重复初始化API的问题:
<template> <div class="container"> <!-- 桌面端视频 --> <div v-if="isDesktop"> <h3 class="youtube_title">desktop video</h3> <YouTube src="https://youtu.be/GQmO52f26Ws" width="540" height="360" /> </div> <!-- 移动端视频 --> <div v-else> <h3 class="youtube_title">mobile video</h3> <YouTube src="https://youtu.be/GQmO52f26Ws" width="280" height="300" class="youtube_padding" /> </div> </div> </template> <script setup> import YouTube from 'vue3-youtube' import { ref, onMounted, onUnmounted } from 'vue' const isDesktop = ref(window.innerWidth >= 591) let resizeHandler = null onMounted(() => { resizeHandler = () => { isDesktop.value = window.innerWidth >= 591 } window.addEventListener('resize', resizeHandler) }) onUnmounted(() => { window.removeEventListener('resize', resizeHandler) }) </script> <style> .youtube_title { margin-bottom: 1rem; } .youtube_padding { /* 保留你的移动端自定义样式 */ } </style>
方案2:复用同一个YouTube组件,动态修改参数
如果不想频繁销毁重建组件,可以只保留一个<YouTube>实例,根据屏幕宽度动态修改宽高和显示文本:
<template> <div class="container"> <h3 class="youtube_title"> {{ isDesktop ? 'desktop video' : 'mobile video' }} </h3> <YouTube src="https://youtu.be/GQmO52f26Ws" :width="isDesktop ? '540' : '280'" :height="isDesktop ? '360' : '300'" :class="{'youtube_padding': !isDesktop}" /> </div> </template> <script setup> import YouTube from 'vue3-youtube' import { ref, onMounted, onUnmounted } from 'vue' const isDesktop = ref(window.innerWidth >= 591) let resizeHandler = null onMounted(() => { resizeHandler = () => { isDesktop.value = window.innerWidth >= 591 } window.addEventListener('resize', resizeHandler) }) onUnmounted(() => { window.removeEventListener('resize', resizeHandler) }) </script> <style> .youtube_title { margin-bottom: 1rem; } .youtube_padding { /* 保留你的移动端自定义样式 */ } </style>
额外优化:统一加载YouTube API
vue3-youtube通常会自动处理API加载,但如果需要手动控制,建议在项目入口文件(如main.js)或根组件中只加载一次API,避免在子组件中重复注入:
// 在main.js或App.vue的onMounted钩子中 onMounted(() => { if (!window.YT) { const script = document.createElement('script') script.src = 'https://www.youtube.com/iframe_api' script.async = true document.body.appendChild(script) } })
内容的提问来源于stack exchange,提问作者bxeom
相关产品推荐
相关产品推荐

