# Nuxt3 嵌入動態 YouTube 如何在 Nuxt3 中動態嵌入 YouTube 影片,支援多種 YouTube 網址格式。 --- ## 功能特色 ✅ 支援多種 YouTube 網址格式: - 標準網址: `https://www.youtube.com/watch?v=VIDEO_ID` - 短網址: `https://youtu.be/VIDEO_ID` - 嵌入網址: `https://www.youtube.com/embed/VIDEO_ID` - 直播網址: `https://www.youtube.com/live/VIDEO_ID` ✅ 自動驗證網址格式 ✅ 響應式設計,支援 RWD ✅ 錯誤處理機制 --- ## 檔案結構 ``` project/ ├── pages/ │ └── video.vue # 頁面組件 └── composables/ └── useYoutubeVerification.js # YouTube 驗證邏輯 ``` --- ## 實作步驟 ### 1. Composable - YouTube 驗證與轉換 建立 `composables/useYoutubeVerification.js`: ```javascript export const useYoutubeVerification = () => { /** * 驗證 YouTube 網址並提取影片 ID * @param {string} data - YouTube 網址 * @returns {string|null} 影片 ID 或 null */ const youtubeVerification = (data) => { if (!data) return null // YouTube 網址格式正則表達式 const youtubeRegex = /(?:youtu\.be\/|youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=|live\/))([^"&?\/\s]{11})/ // 使用 match() 提取影片 ID // match() 返回陣列或 null const match = data.match(youtubeRegex) return match ? match[1] : null } /** * 將 YouTube 網址轉換為嵌入格式 * @param {string} videoUrl - YouTube 網址 * @returns {string|null} 嵌入網址或 null */ const setVideo = (videoUrl) => { const videoId = youtubeVerification(videoUrl) if (!videoId) return null // 返回標準嵌入格式 return `https://www.youtube.com/embed/${videoId}` } return { youtubeVerification, setVideo } } ``` --- ### 2. 頁面組件 建立 `pages/video.vue`: #### Template ```vue <template> <div class="video-container"> <!-- 影片存在且格式正確 --> <template v-if="youtubeVerification(videoUrl)"> <div class="iframe-container"> <iframe class="responsive-iframe" :src="setVideo(videoUrl)" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen ></iframe> </div> </template> <!-- 影片不存在或格式錯誤 --> <template v-else> <div class="error-message"> <p>影片網址格式錯誤或影片不存在</p> <p class="error-hint">請確認 YouTube 網址是否正確</p> </div> </template> </div> </template> ``` #### Script Setup ```vue <script setup> // 引入 YouTube 驗證邏輯 const { youtubeVerification, setVideo } = useYoutubeVerification() // 方式一: 使用 useFetch (推薦 - 適合外部 API) const { data: videoUrl } = await useFetch('/api/video') // 方式二: 使用 useAsyncData + $fetch (推薦 - 更靈活) // const { data: videoUrl } = await useAsyncData('videoUrl', () => $fetch('/api/video')) // 方式三: 直接設定影片網址 (測試用) // const videoUrl = ref('https://www.youtube.com/watch?v=dQw4w9WgXcQ') // 方式四: 從外部 API 取得 // const { data: videoUrl } = await useFetch('https://your-api.com/video-url') </script> ``` #### Style (SCSS) ```vue <style lang="scss" scoped> /* ============================ 方法一: 使用 padding-top 維持比例 ============================ */ /* .iframe-container { position: relative; overflow: hidden; width: 100%; padding-top: 56.25%; // 16:9 比例 (9/16 * 100%) .responsive-iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none; } } */ /* ============================ 方法二: 使用 aspect-ratio (推薦) ============================ */ .iframe-container { width: 100%; aspect-ratio: 16 / 9; // 16:9 比例 overflow: hidden; border-radius: 8px; // 可選: 圓角 .responsive-iframe { width: 100%; height: 100%; border: none; } } /* 錯誤訊息樣式 */ .error-message { padding: 2rem; text-align: center; background: #fff3cd; border: 1px solid #ffc107; border-radius: 8px; p { margin: 0.5rem 0; color: #856404; &.error-hint { font-size: 0.875rem; color: #856404; opacity: 0.8; } } } /* 容器樣式 */ .video-container { max-width: 1200px; margin: 0 auto; padding: 1rem; } /* 響應式設計 */ @media (max-width: 768px) { .video-container { padding: 0.5rem; } } </style> ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up