Skip to content

Commit 409cf1a

Browse files
LyaQanYiclaude
andauthored
fix(tutorial): 增强教程结束时的 UI 清理,修复按钮残留和锁死问题 (Project-N-E-K-O#1171)
* fix(tutorial): 增强教程结束时的 UI 清理,修复按钮残留和锁死问题 * fix(tutorial): address PR Project-N-E-K-O#1171 review comments - 残留节点兜底清理(restoreTutorialInteractionState):优先从 tutorialInteractionStates 还原原始 inline pointerEvents/cursor/userSelect, 仅在没有保存态时退化为清空,避免误把页面上原本就 pointer-events:none 的元素重新激活 (Codex P2 review)。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8a47e5f commit 409cf1a

2 files changed

Lines changed: 54 additions & 5 deletions

File tree

static/universal-tutorial-manager.js

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3254,6 +3254,23 @@ class UniversalTutorialManager {
32543254
delete element.dataset.tutorialDisabled;
32553255
}
32563256
});
3257+
// 兜底:扫描整个文档中残留的 data-tutorial-disabled 节点。
3258+
// 模型管理 MMD 教程结束后曾出现 #vrm-model-select-btn / #mmd-animation-select-btn
3259+
// 等按钮被 pointer-events:none 卡死的情况,根因是 await 期间集合被提前 clear,
3260+
// 后续被遗漏。这里独立做一遍 DOM 兜底清理。
3261+
// 优先从 tutorialInteractionStates 还原原始 inline 值,仅在没有保存态时
3262+
// 退化为清空,避免误把页面上原本就 pointer-events:none 的元素重新激活。
3263+
try {
3264+
document.querySelectorAll('[data-tutorial-disabled]').forEach(element => {
3265+
const state = this.tutorialInteractionStates.get(element);
3266+
element.style.pointerEvents = state?.pointerEvents || '';
3267+
element.style.cursor = state?.cursor || '';
3268+
element.style.userSelect = state?.userSelect || '';
3269+
delete element.dataset.tutorialDisabled;
3270+
});
3271+
} catch (error) {
3272+
console.warn('[Tutorial] 扫描残留 tutorial-disabled 元素失败:', error);
3273+
}
32573274
this.tutorialInteractionStates.clear();
32583275
this.tutorialControlledElements = new Set();
32593276
this.tutorialMarkerDisplayCache = null;
@@ -3743,7 +3760,25 @@ class UniversalTutorialManager {
37433760
}, 500);
37443761

37453762
// 监听事件
3746-
this.driver.on('destroy', () => this.onTutorialEnd());
3763+
// driver.on('destroy') 触发后,先做关键 UI 清理(移除跳过按钮 +
3764+
// 还原 pointer-events),再走完整的 onTutorialEnd 流程。
3765+
// 这两步独立 try/catch,确保即便 onTutorialEnd 任一环节抛错或被早返回,
3766+
// 也不会留下右上角残余按钮 / 模型列表锁死。
3767+
// (MMD/VRM 模型管理教程结束后跳过按钮残留 & 模型列表锁死的修复路径。)
3768+
this.driver.on('destroy', () => {
3769+
console.log('[Tutorial] driver destroy → 执行关键 UI 清理');
3770+
try {
3771+
this.hideSkipButton();
3772+
} catch (error) {
3773+
console.warn('[Tutorial] destroy 清理 hideSkipButton 失败:', error);
3774+
}
3775+
try {
3776+
this.restoreTutorialInteractionState();
3777+
} catch (error) {
3778+
console.warn('[Tutorial] destroy 清理 restoreTutorialInteractionState 失败:', error);
3779+
}
3780+
this.onTutorialEnd();
3781+
});
37473782
this.driver.on('next', () => this.onStepChange().catch(err => {
37483783
console.error('[Tutorial] 步骤切换失败:', err);
37493784
}));
@@ -4677,6 +4712,23 @@ class UniversalTutorialManager {
46774712
* 因此既能给正常结束(onTutorialEnd)复用,也能给启动失败的回退路径复用。
46784713
*/
46794714
_teardownTutorialUI() {
4715+
// 关键 UI 清理:必须先于 _teardownPromise early-return 守卫执行,
4716+
// 且必须幂等。MMD 模型管理教程曾出现:用户走到末步点「完成」后
4717+
// 跳过按钮残留、模型列表按钮 pointer-events:none 卡死。
4718+
// 根因是 teardown 触发时 _teardownPromise 已被前一次未完成的链占用,
4719+
// early-return 直接跳过了 hideSkipButton / restoreTutorialInteractionState。
4720+
// 把这两个操作提到守卫之前,可在任何重复/并发调用下都保证用户能继续操作。
4721+
try {
4722+
this.hideSkipButton();
4723+
} catch (error) {
4724+
console.warn('[Tutorial] hideSkipButton 失败:', error);
4725+
}
4726+
try {
4727+
this.restoreTutorialInteractionState();
4728+
} catch (error) {
4729+
console.warn('[Tutorial] restoreTutorialInteractionState 失败:', error);
4730+
}
4731+
46804732
if (this._teardownPromise) {
46814733
return this._teardownPromise;
46824734
}
@@ -4694,9 +4746,6 @@ class UniversalTutorialManager {
46944746
this._tutorialEndRawReason = null;
46954747
this.currentTutorialStartSource = 'auto';
46964748

4697-
// 移除跳过按钮
4698-
this.hideSkipButton();
4699-
47004749
// 清除刷新定时器
47014750
if (this._refreshTimers) {
47024751
this._refreshTimers.forEach(t => clearTimeout(t));

templates/model_manager.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ <h3 data-i18n="live2d.mmdAnimation.deleteAnimationTitle">删除已导入VMD动
699699
<link rel="stylesheet" href="/static/libs/driver.min.css">
700700

701701
<!-- 通用教程管理器 -->
702-
<script src="/static/universal-tutorial-manager.js?v=12"></script>
702+
<script src="/static/universal-tutorial-manager.js?v=13"></script>
703703
<link rel="stylesheet" href="/static/css/touch-config.css">
704704
<script src="/static/touch-config.js"></script>
705705
<!-- 初始化 -->

0 commit comments

Comments
 (0)