fix: 初始化竞态、用户级覆盖语义与死代码(重构四个控制器)
初始化竞态(已实证):旧 changeConfig() 整个函数体都在 if (this.player) 里,含配置赋值, WE 在 window.load 之前下发属性时被静默丢弃,导致背景/音乐已切到新壁纸、立绘还是旧的。 改为「状态先写、应用后置」:index.js 用单一 state 记录(presetId/audioSource/audioVolume), render() 决定能否立刻应用;setConfig() 无条件记录配置,create() 用记下的配置创建。 - 删除 index.js 里重复的 wallpaperRegisterListener(该 API 在本机 WE 不存在) - 删除 adjustCanvas():播放器每帧自己做 renderer.resize(1) 且已注册 resize 监听, 而它用 getBoundingClientRect() 写 canvas.width 却不乘 DPR,属于有害的重复实现 - 用户级音源/音量覆盖:切壁纸不再清回预设默认值(旧 PresetController 的启发式已移除) - 同源设置改为 no-op:否则两档壁纸共用同一首曲子时一切换就从头播放 - 只在壁纸真的变了才重建播放器,否则拖动音量滑块会触发重新下载 3.6MB 骨架+贴图 - 未知 preset id 保持现状并告警,不再静默回退 验证:属性在 DOMContentLoaded 下发时玩家动画正确为 animation(kv37); 用户自定义音源 custom-track.mp3 与音量 0.2 在切壁纸后完整保留; 重发同一预设时音乐从 1.3s 连续到 1.9s 未重启;未知 id 不崩。 对拍:与重构前同强冻结设置 8 批次 6 配置逐像素完全相同(差异 0)。
This commit is contained in:
1 parent
a391021041
commit
4662856963
8 files changed
+1209
-240
No files matched your search
Vendored
+32
-42
@@ -1,60 +1,50 @@
|
||||
// 负责把「当前预设的 spineConfig」应用到 Spine 播放器上。
|
||||
//
|
||||
// 核心约定:写入与应用分开。WE 可能在 window.load 之前就下发用户属性,那时播放器还不存在;
|
||||
// 旧实现把配置赋值也塞在 `if (this.player)` 里,于是那次配置被静默丢弃,
|
||||
// 结果是"背景与音乐已切到新壁纸、立绘还是旧壁纸"的混合状态(已实测复现)。
|
||||
// 现在 setConfig() 无论如何都记下配置,create() 用记下的配置创建。
|
||||
export default class SpineController {
|
||||
constructor(containerId, config = {}) {
|
||||
constructor(containerId, baseConfig = {}) {
|
||||
this.containerId = containerId;
|
||||
this.config = {
|
||||
this.baseConfig = {
|
||||
alpha: true,
|
||||
premultipliedAlpha: false,
|
||||
showControls: false,
|
||||
showLoading: false,
|
||||
...config,
|
||||
...baseConfig,
|
||||
};
|
||||
|
||||
this.previousConfig = {};
|
||||
|
||||
this.presetConfig = {};
|
||||
this.container = document.getElementById(containerId);
|
||||
this.player = undefined;
|
||||
}
|
||||
|
||||
// 只写状态:与播放器是否存在无关,随时可调用
|
||||
setConfig(presetConfig = {}) {
|
||||
this.presetConfig = presetConfig;
|
||||
if (this.player) this.rebuild();
|
||||
}
|
||||
|
||||
create() {
|
||||
if (!this.player) {
|
||||
const containerId = this.containerId;
|
||||
const config = this.config;
|
||||
this.player = new spine.SpinePlayer(containerId, config);
|
||||
}
|
||||
if (this.player) return;
|
||||
// 每次都用 baseConfig + 当前 presetConfig 现算,避免上一份预设的键残留
|
||||
this.player = new spine.SpinePlayer(this.containerId, {
|
||||
...this.baseConfig,
|
||||
...this.presetConfig,
|
||||
});
|
||||
}
|
||||
|
||||
// 换骨架没有捷径,只能销毁重建
|
||||
rebuild() {
|
||||
this.dispose();
|
||||
this.create();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this.player) {
|
||||
const container = this.container;
|
||||
this.player.dispose();
|
||||
container.innerHTML = "";
|
||||
this.player = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
adjustCanvas() {
|
||||
if (this.player) {
|
||||
const container = this.container;
|
||||
const canvas = container.querySelector("canvas");
|
||||
if (canvas) {
|
||||
const rect = container.getBoundingClientRect();
|
||||
canvas.style.width = "100%";
|
||||
canvas.style.height = "100%";
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeConfig(newConfig = {}) {
|
||||
if (this.player) {
|
||||
this.previousConfig = this.config;
|
||||
this.config = {
|
||||
...this.config,
|
||||
...newConfig,
|
||||
};
|
||||
this.dispose();
|
||||
this.create();
|
||||
}
|
||||
if (!this.player) return;
|
||||
this.player.dispose();
|
||||
this.container.innerHTML = "";
|
||||
this.player = undefined;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user