You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 00:55:13