Nuxt3集成ElevenLabs Audio Native组件失败:仅显示加载文本
解决Nuxt3中ElevenLabs AudioNative组件仅显示加载文本的问题
问题核心原因
- 项目未完成转换:服务器返回
converting: true,说明音频内容还在后台处理,此时组件无法正常渲染 - 脚本执行时机错误:
v-html插入的脚本不会自动执行,且重复加载脚本可能导致冲突 - DOM渲染与脚本加载不同步:脚本加载时,目标DOM元素可能还未渲染完成
分步解决方案
1. 轮询等待项目转换完成
先上传内容获取项目ID,然后定期查询转换状态,直到完成后再渲染组件:
const uploadContentAndGetEmbedCode = async () => { const formData = new FormData(); formData.append("author", "Author Name") formData.append('auto_convert', 'true') formData.append('name', 'ProjectTest') formData.append("file", new Blob(["<html><body><div><p>The text to test for speech</p><h5>More of your content</h5><p>Some more of your content</p></div></body></html>"], { type: "text/html" })); try { // 第一步:创建项目并获取ID const createResponse = await $fetch('https://api.elevenlabs.io/v1/audio-native', { method: 'POST', headers: { 'xi-api-key': '<REMOVED>' }, body: formData }); // 第二步:轮询等待转换完成(每2秒查一次) const pollForCompletion = async (projectId) => { while (true) { await new Promise(resolve => setTimeout(resolve, 2000)); const statusResponse = await $fetch(`https://api.elevenlabs.io/v1/audio-native/${projectId}`, { headers: { 'xi-api-key': '<REMOVED>' } }); if (!statusResponse.converting) { return statusResponse.html_snippet; } } }; // 获取转换完成后的嵌入代码 const finalHtml = await pollForCompletion(createResponse.project_id); audioHtmlSnippet.value = finalHtml; } catch (error) { console.error('请求错误:', error); } };
2. 手动初始化AudioNative组件
v-html不会自动执行插入的脚本,需要在DOM渲染完成后手动加载并触发初始化:
const initAudioNativeWidget = () => { // 移除已存在的脚本避免重复加载 const existingScript = document.querySelector('script[src="https://elevenlabs.io/player/audioNativeHelper.js"]'); if (existingScript) existingScript.remove(); // 动态创建脚本并加载 const script = document.createElement('script'); script.src = 'https://elevenlabs.io/player/audioNativeHelper.js'; script.type = 'text/javascript'; script.onload = () => { // 触发组件初始化(适配脚本的全局函数) if (typeof window.initAudioNative === 'function') { window.initAudioNative(); } }; document.body.appendChild(script); };
3. 监听DOM变化并触发初始化
用watch和nextTick确保DOM渲染完成后再执行脚本:
watch(audioHtmlSnippet, (newVal) => { if (newVal) { nextTick(() => { initAudioNativeWidget(); }); } });
4. 移除重复的脚本加载
删除useHead中重复添加的脚本,避免冲突:
// 删掉这段代码 useHead({ script: [ { src: 'https://elevenlabs.io/player/audioNativeHelper.js', type: 'text/javascript', defer: true, async: true } ] })
整合后的完整组件代码
<template> <section> <div v-html="audioHtmlSnippet"></div> </section> </template> <script setup> import { ref, onMounted, watch, nextTick } from 'vue'; const audioHtmlSnippet = ref(''); const initAudioNativeWidget = () => { const existingScript = document.querySelector('script[src="https://elevenlabs.io/player/audioNativeHelper.js"]'); if (existingScript) existingScript.remove(); const script = document.createElement('script'); script.src = 'https://elevenlabs.io/player/audioNativeHelper.js'; script.type = 'text/javascript'; script.onload = () => { if (typeof window.initAudioNative === 'function') { window.initAudioNative(); } }; document.body.appendChild(script); }; const uploadContentAndGetEmbedCode = async () => { const formData = new FormData(); formData.append("author", "Author Name") formData.append('auto_convert', 'true') formData.append('name', 'ProjectTest') formData.append("file", new Blob(["<html><body><div><p>The text to test for speech</p><h5>More of your content</h5><p>Some more of your content</p></div></body></html>"], { type: "text/html" })); try { const createResponse = await $fetch('https://api.elevenlabs.io/v1/audio-native', { method: 'POST', headers: { 'xi-api-key': '<REMOVED>' }, body: formData }); const pollForCompletion = async (projectId) => { while (true) { await new Promise(resolve => setTimeout(resolve, 2000)); const statusResponse = await $fetch(`https://api.elevenlabs.io/v1/audio-native/${projectId}`, { headers: { 'xi-api-key': '<REMOVED>' } }); if (!statusResponse.converting) { return statusResponse.html_snippet; } } }; const finalHtml = await pollForCompletion(createResponse.project_id); audioHtmlSnippet.value = finalHtml; } catch (error) { console.error('请求错误:', error); } }; watch(audioHtmlSnippet, (newVal) => { if (newVal) { nextTick(() => { initAudioNativeWidget(); }); } }); onMounted(() => { uploadContentAndGetEmbedCode(); }) </script>
内容的提问来源于stack exchange,提问作者redshift
相关产品推荐
相关产品推荐

