+
+ 可视化加载失败
+
+ 该交互模块暂时不可用,课程内容不受影响,请刷新页面重试。
+
+ }>
+ }>
+
+
+
)
}
// 课节正文:use() 挂起等待章节 chunk;loadLesson 按 id 缓存 Promise,
// 重渲染拿到同一实例不会无限 suspend。快照状态属于具体课节,一并放在这里,
// lessonId 变化时组件因 key 重建,状态自然复位。
-function LessonBody({ canonicalLessonId, lessonId, isCompleted, markComplete }) {
+function LessonBody({ canonicalLessonId, isCompleted, markComplete }) {
const lesson = use(loadLesson(canonicalLessonId))
const [playgroundSnapshot, setPlaygroundSnapshot] = useState(null)
const snapshotKeyRef = useRef('')
@@ -34,7 +44,7 @@ function LessonBody({ canonicalLessonId, lessonId, isCompleted, markComplete })
const handlePlaygroundSnapshot = useCallback((snapshot) => {
const current = snapshot?.current || {}
const key = JSON.stringify({
- lessonId,
+ lessonId: canonicalLessonId,
presetId: snapshot?.presetId,
currentStep: snapshot?.currentStep,
total: snapshot?.total,
@@ -46,7 +56,7 @@ function LessonBody({ canonicalLessonId, lessonId, isCompleted, markComplete })
if (snapshotKeyRef.current === key) return
snapshotKeyRef.current = key
setPlaygroundSnapshot(snapshot)
- }, [lessonId])
+ }, [canonicalLessonId])
return (
<>
@@ -76,11 +86,28 @@ export default function AILessonPage() {
const canonicalLessonId = AI_LESSON_ALIASES[lessonId] || lessonId
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
const lessonExists = !!AI_LESSON_INDEX[canonicalLessonId]
+ const asideRef = useRef(null)
+ const contentRef = useRef(null)
const { isCompleted, markComplete, progress } = useCourseProgress(
AI_COURSE_META.id,
AI_TOTAL_LESSONS
)
+ // 换课节:只有正文回到顶部;侧栏目录是独立滚动区,位置保持不动
+ useLayoutEffect(() => {
+ contentRef.current?.scrollTo(0, 0)
+ }, [canonicalLessonId])
+
+ // 首次进入(含深链直达):把目录滚到当前课节附近;之后的滚动交还给用户
+ useEffect(() => {
+ const aside = asideRef.current
+ const active = aside?.querySelector('[data-active="true"]')
+ if (!aside || !active) return
+ const asideRect = aside.getBoundingClientRect()
+ const activeRect = active.getBoundingClientRect()
+ aside.scrollTop += activeRect.top - asideRect.top - aside.clientHeight / 2 + activeRect.height / 2
+ }, [])
+
if (canonicalLessonId !== lessonId && lessonExists) {
return