在 Vue 中使用 Remotion
學習如何將 Remotion Player 整合到 Vue.js 應用程式中,包括 Vite 設定、React 包裝器和響應式數據更新
本指南說明如何將 Remotion 整合到 Vue.js 專案中。
安裝必要套件
安裝 Remotion 和必要的依賴項:
npm i remotion @remotion/player @remotion/cli react react-dom
npm i --save-dev @types/react @types/react-dom @vitejs/plugin-reactpnpm i remotion @remotion/player @remotion/cli react react-dom
pnpm i --dev @types/react @types/react-dom @vitejs/plugin-reactyarn add remotion @remotion/player @remotion/cli react react-dom
yarn add --dev @types/react @types/react-dom @vitejs/plugin-reactbun i remotion @remotion/player @remotion/cli react react-dom
bun --dev @types/react @types/react-dom @vitejs/plugin-react注意:Bun 作為執行時大部分受到支援。在此閱讀更多。
建立 Remotion 資料夾
為了更好地分離關注點,建立一個資料夾來存放你的 Remotion 檔案:
src/remotion
將你的 Remotion 專案或入門範本(例如 HelloWorld)的內容複製到這個新資料夾中。
複製 remotion.config.ts
將 remotion.config.ts 檔案複製到 Vue.js 專案的根目錄,放置在與 package.json 相同的層級。
import { Config } from '@remotion/cli/config';
Config.setVideoImageFormat('jpeg');
Config.setOverwriteOutput(true);為 JSX 配置 TypeScript
要在 Vue.js 中啟用 JSX 支援,請在 tsconfig.app.json 的 compilerOptions 下設定 "jsx": "react":
{
"compilerOptions": {
"jsx": "react",
"jsxImportSource": ""
}
}注意:建議設定
"jsxImportSource": ""以防止建構問題。
為 React 配置 Vite
要在 Vite 中啟用 React 支援,請在 vite.config.ts 中將 react 加入插件中:
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
vue(),
react({
include: /\.(jsx|tsx)$/,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
});為 Vue.js 建立 React 包裝器組件
要在 Vue.js 中嵌入 Remotion 組件,需要建立一個包裝器組件:
在你的 remotion 資料夾中,建立一個名為 PlayerViewWrapper.vue 的檔案:
<template>
<div ref="reactRoot"></div>
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { type PlayerSchema, PlayerView } from '@/remotion/PlayerView';
import { createRoot, type Root } from 'react-dom/client';
import * as React from 'react';
interface PlayerData {
data: PlayerSchema;
}
const playerRef = ref();
const reactRoot = ref<HTMLElement>();
let root: Root;
const emit = defineEmits(['paused']);
const props = defineProps<PlayerData>();
onMounted(() => {
root = createRoot(reactRoot.value!);
render();
});
function render() {
root.render(
React.createElement(PlayerView, {
data: props.data,
playerRefInstance: playerRef,
onPaused: () => emit('paused'),
})
);
}
// 監聽 playerRef 變化(播放器載入後自動播放)
watch(
() => playerRef,
(newData) => {
playerRef.value.play();
},
{ deep: true }
);
// 監聽 data 變化(當 props 改變時重新渲染)
watch(
() => props.data,
(newData) => {
render();
},
{ deep: true }
);
onBeforeUnmount(() => {
if (root) {
root.unmount();
}
});
</script>此包裝器組件將作為 Vue.js 和 Remotion React 組件之間的橋樑。
為 Remotion Player 建立包裝器
- 在你的
remotion資料夾中,建立一個名為PlayerView.tsx的檔案。 - 確保每個
.tsx檔案在頂部明確匯入 React:
import React, { useEffect } from 'react';
import { Player, type PlayerRef } from '@remotion/player';
import { HelloWorld } from '@/remotion/HelloWorld';
import type { Ref } from 'vue';
export interface PlayerSchema {
titleText: string;
titleColor: string;
logoColor1: string;
logoColor2: string;
}
export const PlayerView = ({
data,
playerRefInstance,
onPaused,
}: {
data: PlayerSchema;
playerRefInstance?: Ref<PlayerRef | undefined>;
onPaused?: () => void;
}) => {
const playerRef = React.createRef<PlayerRef>();
useEffect(() => {
if (playerRef.current) {
// 將 React ref 同步到 Vue ref
if (playerRefInstance) {
playerRefInstance.value = playerRef.current;
}
// 當播放器暫停時新增回調
playerRef.current.addEventListener('pause', () => {
onPaused?.();
});
}
}, []);
return (
<Player
ref={playerRef}
component={HelloWorld}
inputProps={data}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{ width: '100%' }}
/>
);
};在 Vue 中使用組件
在你的 Vue 應用程式中使用包裝器組件:
<template>
<div>
<h1>我的影片應用</h1>
<PlayerViewWrapper
:data="videoData"
@paused="handlePaused"
/>
<div class="controls">
<button @click="updateTitle">更新標題</button>
<button @click="updateColor">更改顏色</button>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import PlayerViewWrapper from '@/remotion/PlayerViewWrapper.vue';
import type { PlayerSchema } from '@/remotion/PlayerView';
const videoData = reactive<PlayerSchema>({
titleText: '你好,Vue + Remotion!',
titleColor: '#ffffff',
logoColor1: '#91EAE4',
logoColor2: '#86A8E7',
});
function handlePaused() {
console.log('播放器已暫停');
}
function updateTitle() {
videoData.titleText = '更新後的標題 ' + new Date().toLocaleTimeString();
}
function updateColor() {
videoData.titleColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
}
</script>
<style scoped>
.controls {
margin-top: 16px;
display: flex;
gap: 8px;
}
button {
padding: 8px 16px;
border-radius: 4px;
background: #42b883;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background: #2c9e6e;
}
</style>使用 Nuxt.js
如果你使用 Nuxt.js,需要配置自動匯入並確保 Remotion 只在客戶端執行:
export default defineNuxtConfig({
vite: {
plugins: [
// 需要手動引入 @vitejs/plugin-react
],
},
// 確保 Remotion 模組只在客戶端載入
ssr: false,
});<template>
<div>
<ClientOnly>
<PlayerViewWrapper
:data="videoData"
@paused="handlePaused"
/>
<template #fallback>
<div>載入播放器中...</div>
</template>
</ClientOnly>
</div>
</template>啟動 Remotion Studio
在你的 Vue 專案根目錄中執行:
npx remotion studio渲染影片
你也可以在本地渲染影片:
npx remotion render src/remotion/index.ts MyComposition output.mp4