1
0
Эх сурвалжийг харах

[Fix R4-R4-5] ConversationNav 滚动跟随缓存 wrappers 列表,替代每帧 querySelectorAll(rAF 合并不变)

lizuo 2 долоо хоног өмнө
parent
commit
51803698f9

+ 22 - 2
src/views/ventAI/manageAssistent/components/chat/ConversationNav.vue

@@ -215,7 +215,7 @@
     props.scrollToMessage(pair.startIndex, 'start');
     const pIdx = qaPairs.value.indexOf(pair);
     if (pIdx >= 0) ensureNavLineVisible(pIdx);
-    const wrappers = getContainer()?.querySelectorAll('.message-wrapper');
+    const wrappers = getWrappers();
     const el = wrappers?.[pair.startIndex] as HTMLElement | undefined;
     el?.classList.add('nav-located-highlight');
     setTimeout(() => el?.classList.remove('nav-located-highlight'), 1500);
@@ -239,6 +239,24 @@
 
   // ===== 滚动跟随:消息滚动时,导航选中项实时跟随当前正在阅读的一组问答 =====
   let spyRaf = 0;
+  // [审计-第四轮 R4-5] wrappers 列表缓存。
+  // 原行为:updateActivePairByScroll 在滚动 rAF 回调里每帧对消息容器 querySelectorAll('.message-wrapper')
+  //         全量查询(消息 >100 条时每帧一次 O(n) DOM 查询)。
+  // 现行为:查询结果缓存为数组,仅在消息对数量变化(qaPairs.length watch,已存在于下方)时失效重建;
+  //         另加 O(1) 存活校验(容器是否仍持有首个 wrapper),防 DOM 整批替换(如切换任务)后用到游离节点。
+  // 为什么:滚动期每帧省一次 O(n) 查询,rAF 合并不变;消息 DOM 只随消息增删变化,必经 qaPairs.length 变化。
+  let cachedWrappers: Element[] | null = null;
+  const getWrappers = (): Element[] => {
+    const container = getContainer();
+    if (!container) return [];
+    if (cachedWrappers && cachedWrappers.length > 0 && !container.contains(cachedWrappers[0])) {
+      cachedWrappers = null;
+    }
+    if (!cachedWrappers) {
+      cachedWrappers = Array.from(container.querySelectorAll('.message-wrapper'));
+    }
+    return cachedWrappers;
+  };
   const updateActivePairByScroll = () => {
     const pairs = qaPairs.value;
     const container = getContainer();
@@ -246,7 +264,7 @@
       activeMessage.value = null;
       return;
     }
-    const wrappers = container.querySelectorAll('.message-wrapper');
+    const wrappers = getWrappers();
     // 以视口上部 1/3 处为判定线:起始位置越过判定线的一组即为当前阅读组;触底时强制选中最后一组
     const mark = container.scrollTop + container.clientHeight * 0.35;
     let current = 0;
@@ -275,9 +293,11 @@
   };
 
   // 消息增减(新问答、加载历史、切换任务)后同步一次选中状态
+  // [审计-第四轮 R4-5] 消息对数量变化意味着 .message-wrapper DOM 已增删,缓存的 wrappers 列表随之失效
   watch(
     () => qaPairs.value.length,
     () => {
+      cachedWrappers = null;
       nextTick(updateActivePairByScroll);
     },
     { immediate: true }