Remotion LabRemotion Lab
程式碼片段在 iframe 中嵌入 Player

在 iframe 中嵌入 Player

了解如何將 Remotion Player 嵌入 iframe,處理跨域通訊與尺寸自適應問題。

在 iframe 中嵌入 Player

當你需要在第三方網站、CMS 或不同技術棧的前端中展示 Remotion 影片時,透過 <iframe> 嵌入是最實用的方案。

為什麼要用 iframe?

  • 隔離 React 和 Remotion 的依賴,避免版本衝突
  • 讓不使用 React 的網站也能嵌入影片播放器
  • 安全地在第三方內容中展示影片
  • 便於在 CMS(如 WordPress、Webflow)中使用

基本架構

嵌入方式分為兩個部分:

  1. Host 頁面:建立一個獨立的 Next.js / Vite 頁面,內含 <Player> 元件
  2. 嵌入方:用 <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 回報自身高度給父頁面。

延伸閱讀