Browse Source

fix: 优化目录跳转匹配逻辑,支持多种标题格式

- 规范化文本比较(处理空格、特殊字符)
- 先匹配 h1-h6 标题元素
- 再匹配带粗体样式的 span
- 最后尝试全文搜索
- 支持双向包含匹配
何文松 4 tuần trước cách đây
mục cha
commit
2fc901eb93
1 tập tin đã thay đổi với 43 bổ sung10 xóa
  1. 43 10
      frontend/vue-demo/src/views/Editor.vue

+ 43 - 10
frontend/vue-demo/src/views/Editor.vue

@@ -514,39 +514,72 @@ function getTocBullet(level) {
   return bullets[Math.min(level - 1, bullets.length - 1)]
 }
 
+// 规范化文本(移除多余空格、特殊字符)
+function normalizeText(text) {
+  if (!text) return ''
+  return text
+    .replace(/\s+/g, ' ')  // 多个空格变一个
+    .replace(/[\u00A0]/g, ' ')  // 不间断空格转普通空格
+    .trim()
+}
+
 // 滚动到指定章节(通过标题元素匹配)
 function scrollToHeading(item) {
-  const titleText = item.title || item.text
+  const titleText = normalizeText(item.title || item.text)
   if (!titleText) return
   
-  // 在文档内容区域中查找标题元素 (h1, h2, h3, h4, h5, h6)
+  // 在文档内容区域中查找标题元素
   const editorContent = document.querySelector('.editor-content')
   if (!editorContent) return
   
-  // 查找所有标题元素
+  // 1. 先查找 h1-h6 标题元素
   const headings = editorContent.querySelectorAll('h1, h2, h3, h4, h5, h6')
   
+  // 精确匹配
   for (const heading of headings) {
-    // 获取标题的纯文本内容(去除空格比较)
-    const headingText = heading.textContent?.trim()
-    if (headingText && headingText === titleText.trim()) {
-      // 滚动到标题元素
+    const headingText = normalizeText(heading.textContent)
+    if (headingText === titleText) {
       heading.scrollIntoView({ behavior: 'smooth', block: 'start' })
       highlightElement(heading)
       return
     }
   }
   
-  // 如果精确匹配失败,尝试包含匹配
+  // 包含匹配(标题包含目录文本,或目录文本包含标题)
   for (const heading of headings) {
-    const headingText = heading.textContent?.trim()
-    if (headingText && headingText.includes(titleText.trim())) {
+    const headingText = normalizeText(heading.textContent)
+    if (headingText && (headingText.includes(titleText) || titleText.includes(headingText))) {
       heading.scrollIntoView({ behavior: 'smooth', block: 'start' })
       highlightElement(heading)
       return
     }
   }
   
+  // 2. 如果 h1-h6 没找到,尝试查找带粗体样式的段落(可能是标题)
+  const boldSpans = editorContent.querySelectorAll('span[style*="font-weight:bold"], strong, b')
+  for (const span of boldSpans) {
+    const spanText = normalizeText(span.textContent)
+    if (spanText === titleText || spanText.includes(titleText) || titleText.includes(spanText)) {
+      const parent = span.closest('p, div, h1, h2, h3, h4, h5, h6') || span
+      parent.scrollIntoView({ behavior: 'smooth', block: 'start' })
+      highlightElement(parent)
+      return
+    }
+  }
+  
+  // 3. 最后尝试全文搜索
+  const allElements = editorContent.querySelectorAll('p, div, span')
+  for (const el of allElements) {
+    const elText = normalizeText(el.textContent)
+    // 检查元素直接包含的文本(不是子元素的文本)
+    if (elText === titleText) {
+      el.scrollIntoView({ behavior: 'smooth', block: 'start' })
+      highlightElement(el)
+      return
+    }
+  }
+  
+  console.warn('未找到章节:', titleText)
   ElMessage.warning('未找到对应章节')
 }