fix(workbench): 剪辑台白屏(分镜视频列表 icon 传 emoji 导致 <component :is> 渲染崩溃) - #33
Open
37389744 wants to merge 1 commit into
Open
fix(workbench): 剪辑台白屏(分镜视频列表 icon 传 emoji 导致 <component :is> 渲染崩溃)#3337389744 wants to merge 1 commit into
<component :is> 渲染崩溃)#3337389744 wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
项目生成了分镜视频后,打开「视频剪辑」(剪辑台)页面出现白屏;未生成分镜视频时页面正常。
环境
HBAI-Ltd/Toonflow-web3.5.12复现步骤
(对照组:不生成任何分镜视频,直接打开「视频剪辑」,页面正常。)
根因
mediaLibrary.vue使用 Vue 动态组件渲染素材图标::is="item.icon"期望传入的是 IconPark 图标组件名。同文件中的转场/特效/滤镜列表都是合法组件名:但在
workbench/index.vue的editFootage()里,给三个素材列表写入的是 emoji 字符串,而非组件名:崩溃机制(已实测确认)
Vue 3 的
resolveDynamicComponent("🎬")找不到名为🎬的组件,于是把它当作原生 HTML 标签处理,调用document.createElement("🎬")。实测该调用直接抛异常:该异常发生在 Vue 渲染过程中,无法被 try-catch 捕获,导致整个剪辑台组件树渲染失败 → 白屏。
精确触发条件(三个条件同时满足)
activeTab是某个素材 tabvideo(默认激活)/ 媒体media/ 图片imagegetMaterialData返回的data.video非空(分镜视频);或媒体素材、图片素材有数据item.thumbnail为假值extractVideoThumbnails内部 fetch + WebAV 解码),首次渲染时必然为空 → 走v-else分支由于条件 ③ 在首次渲染时必然满足,所以只要「分镜视频」tab(默认激活)有数据,打开剪辑台就必然白屏,不存在「有视频但侥幸不白屏」的边界情况。
🎥(媒体素材)、🖼️(图片素材)是同款 bug,切到对应 tab 且有数据时同样触发。为什么「以前有视频也不白屏」
icon: "🎬"与<component :is="item.icon">这两处是同一次提交引入的:该提交之前不存在这个 emoji icon(也没有这个渲染方式),所以更早的版本有视频也不会白屏。此 bug 自 2026-03-26 起一直潜伏。
修复方法(两个方案,任选其一)
方案 A:直接删除 emoji icon(当前 PR 已采用)
initialVideoItems.value = data.video.flatMap((item, index) => { if (Array.isArray(item.video)) { return item.video.map((subItem, subIndex) => ({ id: `video-${subItem.id}`, type: "video", name: "#" + ..., duration: subItem.duration || 0, - icon: "🎬", color: "...", url: subItem.filePath, selected: item.videoId == subItem.id, })); } }); - mockMediaItems.value = videoList.map((item) => ({ ..., icon: "🎥", ... })); - mockImageItems.value = imageList.map((item) => ({ ..., icon: "🖼️", ... }));去掉后
item.icon为undefined,<component :is="undefined">渲染空节点;缩略图加载完成后走v-if="item.thumbnail"正常显示缩略图。方案 B:替换为合法的 IconPark 图标(保留图标)
项目已全量引入 IconPark(
@icon-park/vue-next/es/all),且mediaData.ts中已在使用这些图标名,可直接复用:initialVideoItems.value = data.video.flatMap((item, index) => { if (Array.isArray(item.video)) { return item.video.map((subItem, subIndex) => ({ id: `video-${subItem.id}`, type: "video", name: "#" + ..., duration: subItem.duration || 0, - icon: "🎬", + icon: "i-video", color: "...", url: subItem.filePath, selected: item.videoId == subItem.id, })); } }); - mockMediaItems.value = videoList.map((item) => ({ ..., icon: "🎥", ... })); + mockMediaItems.value = videoList.map((item) => ({ ..., icon: "i-video-file", ... })); - mockImageItems.value = imageList.map((item) => ({ ..., icon: "🖼️", ... })); + mockImageItems.value = imageList.map((item) => ({ ..., icon: "i-pic", ... }));映射:
🎬(分镜视频)→i-video;🎥(媒体素材)→i-video-file;🖼️(图片素材)→i-pic。均为合法组件名,可正常渲染,且保留了原图标语义。相关文件
src/views/production/components/workbench/index.vue(editFootage()中的icon字段)src/views/production/components/workbench/editVideo/mediaLibrary.vue(<component :is="item.icon">)