在 iframe 中嵌入 Player
了解如何將 Remotion Player 嵌入 iframe,處理跨域通訊與尺寸自適應問題。
在 iframe 中嵌入 Player
當你需要在第三方網站、CMS 或不同技術棧的前端中展示 Remotion 影片時,透過 <iframe> 嵌入是最實用的方案。
為什麼要用 iframe?
- 隔離 React 和 Remotion 的依賴,避免版本衝突
- 讓不使用 React 的網站也能嵌入影片播放器
- 安全地在第三方內容中展示影片
- 便於在 CMS(如 WordPress、Webflow)中使用
基本架構
嵌入方式分為兩個部分:
- Host 頁面:建立一個獨立的 Next.js / Vite 頁面,內含
<Player>元件 - 嵌入方:用
<iframe>指向該頁面
步驟一:建立 Player 頁面
建立一個專門的路由頁面,例如 /player,只渲染播放器本身:
// app/player/page.tsx (Next.js App Router)
import { Player } from "@remotion/player";
import { MyComposition } from "../../remotion/MyComposition";
export default function PlayerPage() {
return (
<div
style={{
width: "100%",
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "#000",
margin: 0,
padding: 0,
}}
>
<Player
component={MyComposition}
durationInFrames={300}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{ width: "100%" }}
controls
autoPlay
loop
/>
</div>
);
}步驟二:在其他頁面用 iframe 嵌入
<!-- 靜態 HTML 嵌入範例 -->
<iframe
src="https://your-app.com/player"
width="100%"
height="auto"
style="aspect-ratio: 16/9; border: none;"
allowfullscreen
allow="autoplay; fullscreen"
></iframe>// React 元件中的嵌入範例
export const EmbedPlayer: React.FC = () => {
return (
<div style={{ position: "relative", paddingBottom: "56.25%", height: 0 }}>
<iframe
src="https://your-app.com/player"
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
border: "none",
}}
allowFullScreen
allow="autoplay; fullscreen"
/>
</div>
);
};透過 URL 參數傳遞 Props
若需要從外部控制影片內容,可透過 URL 查詢參數傳遞資料:
// app/player/page.tsx - 讀取 URL 參數
import { useSearchParams } from "next/navigation";
import { Player } from "@remotion/player";
import { TitleCard } from "../../remotion/TitleCard";
export default function PlayerPage() {
const searchParams = useSearchParams();
const title = searchParams.get("title") ?? "預設標題";
const color = searchParams.get("color") ?? "#ffffff";
return (
<Player
component={TitleCard}
inputProps={{ title, color }}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{ width: "100%" }}
controls
/>
);
}<!-- 帶參數的嵌入 -->
<iframe
src="https://your-app.com/player?title=你好世界&color=%230099ff"
width="100%"
style="aspect-ratio: 16/9; border: none;"
></iframe>跨域通訊(postMessage)
需要雙向互動時,使用 window.postMessage 在父頁面與 iframe 之間溝通:
// iframe 內的 Player 頁面:監聽外部指令
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
// 安全驗證來源
if (event.origin !== "https://trusted-parent.com") return;
if (event.data.type === "SEEK") {
playerRef.current?.seekTo(event.data.frame);
}
if (event.data.type === "PAUSE") {
playerRef.current?.pause();
}
};
window.addEventListener("message", handleMessage);
return () => window.removeEventListener("message", handleMessage);
}, []);// 父頁面:向 iframe 發送指令
const iframeRef = useRef<HTMLIFrameElement>(null);
const seekTo = (frame: number) => {
iframeRef.current?.contentWindow?.postMessage(
{ type: "SEEK", frame },
"https://your-app.com"
);
};響應式尺寸處理
維持 16:9 比例的 CSS 技巧:
/* 方法一:padding-bottom hack(傳統方式) */
.video-wrapper {
position: relative;
padding-bottom: 56.25%; /* 9/16 = 56.25% */
height: 0;
overflow: hidden;
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* 方法二:aspect-ratio(現代瀏覽器) */
iframe.player {
width: 100%;
aspect-ratio: 16 / 9;
border: none;
}安全性設定
// 在 Next.js 中設定允許嵌入的 Content Security Policy
// next.config.js
const nextConfig = {
async headers() {
return [
{
source: "/player",
headers: [
{
key: "X-Frame-Options",
value: "ALLOWALL", // 或指定特定來源:ALLOW-FROM https://trusted.com
},
{
key: "Content-Security-Policy",
value: "frame-ancestors 'self' https://trusted-parent.com",
},
],
},
];
},
};常見問題
自動播放被瀏覽器封鎖?
大多數瀏覽器要求影片靜音才能自動播放。在 <Player> 上加入 muted 屬性,或引導使用者點擊後再播放。
iframe 高度無法自適應內容?
建議固定使用 aspect-ratio CSS 屬性,或透過 postMessage 讓 iframe 回報自身高度給父頁面。