Files
ArtPlayer/refactor/changes/2026-09-11-CORE-14-setting.md
T

106 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CORE-14 设置树、渲染与布局
状态:完成。设置目录的 TS 拆分、生命周期、失败恢复、布局和交互已通过最终安装包验收。以下各批记录保留当时的进度与失败原因,当前结论以末尾最终交付证据为准。
## 已接入的源码
setting/model.ts 管理树遍历、查找、结构预检、自动名称及父级绑定。setting/index.ts 的 traverse/format/find 委托该模型;仍保留按选项数组缓存面板的专用管理器,不把它强行套进 Control 返回类型。add/update 返回原条目、remove 返回 undefined、find 缺失返回 null;当前公开 d.ts 保持不变,BASE-TYPE-07 的兼容视图出口仍需 CORE-21 完成。
父级、所在数组、父级数组和事件列表保留非枚举、不可配置 getter;WeakMap 允许同一条目从旧父级移除后重新绑定,getter 函数及事件数组身份保持。遍历保留前序和回调期间添加子节点的可见性。正常显式名称和自动计数规则保留;自动名称遇到整树显式名称时跳过冲突 ID。重复名称、循环/重复条目或不可重定义的外来绑定先预检,不先给前面的条目写入元数据。外部任意 setter/Proxy 抛错的事务边界,以及同时跨活动实例共享同一条目对象,仍需随管理器和资源阶段核对,当前不宣称已覆盖。
setting/layout.ts 将尺寸计算与 DOM 测量分开,面板宽度不超过播放器扣除 padding 后的空间,高度限制在实际控件上方,可滚动访问嵌套内容。padding 从 bottom 的已计算样式读取,支持 CSS 单位解析;控件中心按播放器缩放换算。正常右侧溢出时保持旧 CSS right 锚点,移动端/旋转分支保留原定位策略。动态尺寸观察、长文本、旋转/移动端和完整旧新组合仍需继续验证。
## 首批验证与待办
新增 7 项模型与 3 项布局单元测试;类型正反例覆盖保留自定义字段、数字计数器和 nullable 查找。浏览器新旧对照覆盖条目返回/绑定、移动条目、名称冲突、320x180 的超宽嵌套面板及真实点击最后一项。初轮 24 项三浏览器通过并已检查旧新截图:旧面板裁切在容器外,候选可滚动选择。最终锚点兼容调整后,24 项专项复跑通过;yarn ci:check 共 187 项通过(158 单元、4 工程、25 基线),112 个生产 TS 文件严格检查。见 [阶段证据](../baselines/setting-model-layout-validation.json)。尚未完成整个 CORE-14 或安装包回归。
首批结束时计划迁移 manager/types、selection、render 与内置设置(第二批完成情况见下文),建立条目/面板作用域,处理删除子树、缓存面板更新、过期异步回调和 mounted 定时器。补充失败与重入、默认高亮、长文本、实际窄尺寸变化、旧插件交互,之后构建并验证安装 UMD/legacy、公开类型消费和最终文档。BASE-DOM-02 此时仍 open。
package.json 将 setting-model.test.js 与 setting-layout.test.js 纳入 test:unit;无新增依赖、锁文件或版本变更。任务未完成,尚不提交本任务,不推送或发布。
## 第二批:渲染、回调与条目资源
render.ts 保留 div/类名、item 的动态 html/icon/tooltip/switch/range 描述符、数据写入和条目身份;管理器入口继续转发 createHeader/createItem/render。selection.ts 保留原 callback this、item、DOM 与 Event,range 的同步值写入和选择 default 标志;按实际写入对象隔离异步结果,兄弟 selector 共用父项代次,更新/删除关闭旧条目作用域。原始失败用 console.warn 报告,不吞掉原异常身份。没有取消用户自己的异步 SDK 工作。
resources.ts 管理条目作用域、DOM 事件与内置 Emitter 订阅。删除/更新父项时递归释放子项并移除其 selector 数组对应的缓存面板;清理失败仍尝试其余事件。注册中重入销毁会释放刚返回的监听器。延迟 mounted 绑定本次条目与 DOM,移除/更新取消旧定时器;mounted 的同步失败或返回 Promise 拒绝会报告,不把其返回值当 disposer。
playbackRate/aspectRatio/flip/subtitleOffset 四个内置设置已迁移 TS;订阅随条目关闭。数值/字符串断言仅对应内置工厂自己创建的 selector 值,不改变运行时转换。6 项资源单元用例与新旧浏览器用例覆盖乱序、更新后写入、拒绝身份、子树缓存/监听器、延迟 mounted、订阅重复及移除。最终同步导航异常保护已通过单元及专项复验;设置专项 60 项三浏览器通过,CI 193 项通过(164 单元、4 工程、25 基线),120 个生产 TS 文件严格检查。见 [第二批阶段证据](../baselines/setting-resources-validation.json),该记录明确为 partial。
尚待:管理器转 TS 与专用继承类型边界;add/update/渲染失败时的对象、DOM、面板和监听器回滚;子面板 header 的独立失败清理;跨实例共享/复用和非扩展对象预检;动态尺寸观察、长文本、switch/range 与重入/销毁专项;完整核心/旧插件与最终 UMD/legacy 安装产物。不能用当前已通过专项替代这些剩余验收。
## 第三批:管理器、根事件与失败处理
index.ts 保留实际 Component 原型继承,用最小构造类型视图表达 Setting 自己的数组缓存及返回约定,没有通过双重断言伪装成通用组件。新增管理器类型正反例,验证 add 保留输入自定义字段、find 可为 null、remove 为 void。
events.ts 接管 blur/focus/resize 和尺寸观察,实例关闭后解绑。ResizeObserver 观察播放器与控件;MutationObserver 观察播放器 class/style,并在缺少 ResizeObserver 时补充控件变化。没有 ResizeObserver 的环境仍依赖已有 window/core resize 信号发现外部容器尺寸变化,不能宣称自动发现所有祖先 CSS 修改。
最初动态布局测试三浏览器均失败:宽度已收缩到 300px,但面板高度仍为 124px,目标为 78px。补上 style 观察后仍失败,证实只增加观察不够;设置面板 `transition: all` 使 getComputedStyle(bottom) 在回调时返回过渡起点。现在额外监听面板自身 bottom 的 transitionend,过渡结束后重算,保持现有动画。6 项原生观察/回退专项通过,随后完整设置专项 72 项通过;销毁后晚到观察与 resize 均不调用管理器。
第三批 yarn ci:check 194 项通过(165 单元、4 工程、25 基线),122 个生产 TS 文件严格检查;设置专项 72 项为当前工作区构建,三浏览器无重试、跳过或未处理异常。源码、报告、候选构建及失败记录指纹见 [第三批阶段证据](../baselines/setting-manager-validation.json),仍明确为 partial。
formatTree 新增非扩展对象和不可写自动名称预检,重复名称保持原 ArtPlayerError。add 失败移除本次追加位置;格式化成功后才释放新条目的部分渲染资源,避免无效共享子树触及已有监听器。remove 即使清理失败也继续移除原 DOM 并恢复根面板,再汇总异常。资源树释放有已访问集合,避免外部后续构造循环导致无限递归。
浏览器失败注入覆盖重复名称、同一对象/共享子项、不可扩展对象、html getter 抛错、渲染阶段抛错后的 mounted 取消、再次添加和旧条目可用性。移除失败测试的首版直接向 $events 塞入任意函数,但真实 Events.remove 只处理登记过的监听器,导致三项断言失败;现改为真实 art.proxy 登记与 event-removal 钩子注入,验证原错误身份、后续清理、DOM 删除和兄弟条目均正常。保留失败日志,不以假函数改变生产事件约定。
仍未解决的边界:update 的原对象/描述符/监听器事务恢复、面板创建失败后的缓存与 header 独立清理、重入时的归属以及跨活动实例共享条目。任意 getter/setter/Proxy 的外部副作用不能承诺通用回滚;失败后的新输入可能保留已安装的隐藏元数据。长文本、switch/range、移动端/旋转、完整旧插件组合和最终安装包仍需验收。前两批阶段记录保留当时源码路径与指纹,不改写为最新完成证据。
## 第四批:面板作用域与新面板渲染恢复
panels.ts 管理按选项数组缓存的面板作用域,条目作用域挂到所属面板;返回按钮由面板持有,并仍登记在父项的公开 $events 数组中。失败、删除子树或销毁时释放其监听器、延迟 mounted、缓存和 DOM。清理返回按钮时从原事件数组移除对应登记,不影响父项其他监听器,也不重复移除已被父项释放的监听器。
checkpoint.ts 不调用用户 getter,保存条目的原属性描述符及直接传入 html/icon/tooltip 的节点位置。新面板创建若在 header、条目或 resize 阶段抛错,释放部分面板,恢复原输入节点和描述符、之前活动面板以及 height/width/left/right,调用者仍收到原始错误。归属检查避免恢复已经由别的面板接管的条目;创建 header 时重入删除父项或销毁实例,后续条目不会继续创建。该阶段没有把这些保证扩展为所有 update 或任意用户重入均已解决。
新增 15 项三浏览器测试,覆盖三种失败阶段、失败后正常重试、原 DOM 节点身份与位置、mounted 不重复、父项监听器数量、返回按钮和删除后的迟到点击,以及 header 创建中的 remove/destroy 重入。设置专项共 87 项通过。初次测试在回滚后等待定时器才比较 style,与正常 ResizeObserver 后续布局混在一起,九项失败;分开记录同步回滚和下一轮布局后,证实同步恢复正确。布局失败注入钩子随后也需在同步调用结束后撤销,避免测试自己的异常污染异步观察器。保留两轮失败报告和前后样式附件,未放宽未处理错误检查。
第四批 CI 194 项通过(165 单元、4 工程、25 基线),124 个生产 TS 文件严格检查。完整工作区 UMD 三浏览器 429 项通过,含设置 87 项以及现有播放、切源、章节插件、全屏、生命周期等检查;无重试、跳过或未处理异常。专项与完整运行的候选构建指纹一致,见 [第四批阶段证据](../baselines/setting-panels-validation.json)。这是当前工作区构建证据,不能替代最终安装包和 legacy 验收。
仍需完成:已缓存面板切换及 update 的失败/重入恢复、跨实例条目复用、长文本与 switch/range、移动端/旋转、最终安装 UMD/legacy 回归和包指纹核对。CORE-14 继续 doing,风险尚未关闭,未提交本任务。
## 第五批:设置项 update 事务与重入
update.ts 保留原条目身份和返回值,在赋值前暂停旧子树,渲染成功后才释放旧资源。resources.ts 让暂停的作用域暂存旧监听器,公开 $events 数组身份不变,新一代登记写入原数组;activity.ts 阻止暂停期间的旧回调及异步写入。回滚恢复原监听器,不重新登记,也不重复执行已经运行的 mounted;成功则释放旧代,新代继续工作,销毁时两代都释放。
checkpoint.ts 保存框架管理的 switch/range 闭包状态,恢复 range 原数组引用、内容和原生 input 的边界、步进及值;DOM 检查点恢复实际旧节点及其属性,不用克隆节点替代原节点。赋值、整树校验、条目渲染或最终 render 失败时恢复这些受管理状态,调用者仍收到原错误。提交后若旧资源清理异常,保留已经成功的新行并报告清理错误,不假装已释放的旧资源还能恢复。
按 Reflect.ownKeys 的顺序读取可枚举自有字段,保留通常的 Object.assign 读写顺序,同时在每个用户读取/写入之后检查当前操作。重入新 update、remove、destroy 或后代 update 会终止旧操作;删除祖先先取消其后代的未完成更新。渲染持有自己的操作/作用域,旧 getter 在新行完成后继续返回或抛错,也不能覆盖新句柄或清理新行。任意自定义 setter/Proxy 的外部副作用,以及任意覆写方法在返回前自行发起的额外操作,不能承诺通用回滚。
4 项新增资源单元检查覆盖恢复原登记、只提交新代、销毁两代及清理异常仍恢复旧监听器。新增独立 setting-update.spec.js,覆盖四个失败阶段的 range/DOM/监听器身份、失败后重试、switch 显示状态、同项和父子重入、祖先删除,以及 icon/switch/range 渲染 getter 的重入。此前 87 项设置专项和第一轮新增 27 项均通过;扩展重入检查后的 123 项也通过。最后补充的控制句柄检查随本轮完整运行验证,以下阶段证据以最终完整运行指纹为准,不把较早专项当作最后源码的证据。
第五批最终 CI 198 项通过(169 单元、4 工程、25 基线),126 个生产 TS 文件严格检查;工作区 UMD 完整三浏览器 471 项通过,其中设置相关 129 项,无重试、跳过或未处理异常。见 [第五批阶段证据](../baselines/setting-update-validation.json),包含最终源码/测试/构建和报告指纹。尚未运行本任务最终安装包和 legacy 验收。
仍需完成:直接切换已缓存面板时的失败恢复、跨实例共享/复用、长文本与完整 switch/range 交互、移动端/旋转、最终安装 UMD/legacy 与打包类型验收。当前公开 d.ts 未变,CORE-14 仍 doing,不关闭风险、不提交未完成任务。
## 第六批:缓存导航恢复与实例归属
render 的缓存分支现在也处理 resize 失败,恢复之前的活动面板及布局属性,保留缓存 DOM 和监听器。每次导航有独立代次;失败前若重入导航、删除面板或销毁实例,外层失败不再覆盖较新的结果。导航专项最初三项失败源于测试假定根面板与子面板尺寸必不相同,实际两者此时均为两行;活动面板和 class 断言证明重入导航正确,尺寸相等不是回滚的证据。修正该断言并保留初轮报告。
实际旧/新对照复现 BASE-DOM-08:同一条目给两台活动播放器使用,旧发布版的第二台没有条目,但第一台仍可点击;归属保护前的候选会重新绑定到第二台并释放第一台监听器。现在整树预检拒绝仍由另一活动树持有的条目,抛出 ArtPlayerError,两个树及先前监听器都不修改。没有静默克隆条目,因为那会改变 add/update 返回原对象及回调引用约定。此前这种共享本身不能正常显示两台播放器,因此登记为旧缺陷修正;同时显示时使用各自的条目对象,回调函数仍可共用。
owner 状态不直接保存播放器或 manager 对象,销毁时清空树和作用域引用,避免绑定保留旧实例。关闭中的作用域也视为非活动;旧树 remove 或实例 destroy 后,原条目/子树可交给另一实例使用,父级绑定随之更新,隐藏 getter 与 $events 数组身份保留,原实例晚到清理不会影响新实例。新增两项模型单元和 24 项归属/导航三浏览器检查,均通过;包含冲突 add 不改旧树、原对象移交、旧节点迟到点击及新回调 this。
第六批最终 CI 200 项通过(171 单元、4 工程、25 基线),126 个生产 TS 文件严格检查;工作区 UMD 完整三浏览器 495 项通过,其中设置相关 153 项,无重试、跳过或未处理异常。见 [第六批阶段证据](../baselines/setting-ownership-validation.json),保留旧/新共享对象的初始诊断和最终构建指纹。
仍需完成长文本、完整 switch/range 原生交互、移动端/旋转,以及 CORE-14 最终安装 UMD/legacy、类型消费和文件指纹验收。BASE-DOM-08 与其他 CORE-14 风险保持 open,任务保持 doing。
## 第七批:原生交互、长文本与旋转
setting-interaction.spec.js 使用真实键盘与指针事件核对 range 的 input/change 次序、每次同步值、回调 this/条目/DOM 与最终 tooltip,并用真实点击切换 switch。移动 UA/视口与触摸事件结合本地视频和实际内置 autoOrientation,验证正常与旋转状态的嵌套菜单滚动和最后一项选择;没有把这些测试标成实体手机验收。
长文本初轮在三个引擎复现控件被挤出行内,旧版与候选都存在。setting.less 让标签与提示缩短显示,给原生控件及图标保留宽度,并保留左右内容间隔;文本仍完整保留在 DOM。已检查旧/新长文本和旋转截图,新版 range/switch 可见且可通过键盘/指针操作。交互专项 18 项通过;额外 add 重入检查合入后,交互与更新两组共 66 项通过。
收尾审查补上 registration.ts:外层 add 的 getter 在内层成功 add/update 同一对象后抛错时,旧操作不能移除新行。记录新的注册归属,remove/update 使旧注册失效;保留外层原始异常及内层成功结果。最终打包验收将覆盖最新源码,不以此前局部运行替代它。
本任务的完整浏览器矩阵指仓库现有核心、历史核心及章节插件组合和契约套件;全部生态包/SDK 的专项迁移与最终发布矩阵仍由对应后续任务负责。BASE-TYPE-07 保持开放至 CORE-21 的兼容公开类型出口,CORE-14 不伪造运行时返回值来迁就旧声明。
## 最终交付证据
- yarn ci:check:200 项通过(171 单元、4 工程、25 基线),127 个生产 TS 文件严格检查;核心 122、chapter 5。
- 核心构建与 i18n 生成成功。核心/chapter 实际 tarball 仓库外安装:27 项运行时、五组类型零诊断。
- 实际安装 UMD 与 legacy 各 519 项三浏览器通过,其中各含 177 项设置相关检查;无重试、跳过、flaky 或未处理页面异常。
- [最终验证记录](../baselines/setting-validation.json) 核对全部核心源码与构建快照、三个分发格式与 tarball/docs/compiled、公开声明、包内架构文档、22 个语言文件和独立分发许可。阶段失败与原始旧行为记录仍保留。
- legacy 首次启动时,临时映射中的包路径被重复拼接,服务尚未启动即失败;已改为 Resolve-Path 得到的绝对产物路径,保留启动失败日志。最终验收核对实际映射的包内字节,不把启动失败计作通过或测试重试。
- 关闭 BASE-DOM-02/06/07/08 与 BASE-LIFE-12/13/14。BASE-TYPE-07 保留给 CORE-15/18/21 等公开类型后续责任;本任务不改变旧公开声明来掩盖实际 item/null/void 返回。
- 移动端检查采用真实引擎、触摸事件、模拟 UA/视口和实际 autoOrientation,未宣称实体设备、全部外部 SDK、远端 CI 或完整生态发布验收。
本任务独立本地提交,不推送或发布。当前 214 项中 50 完成、164 待办;下一项 CORE-15 字幕获取、解析和渲染。