|
|
@@ -120,7 +120,6 @@
|
|
|
>
|
|
|
<span class="toc-bullet">{{ getTocBullet(item.level) }}</span>
|
|
|
<span class="toc-text">{{ item.title || item.text }}</span>
|
|
|
- <span class="toc-page" v-if="item.pageNum || item.page">{{ item.pageNum || item.page }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="toc-empty" v-else>
|
|
|
@@ -515,43 +514,36 @@ function getTocBullet(level) {
|
|
|
return bullets[Math.min(level - 1, bullets.length - 1)]
|
|
|
}
|
|
|
|
|
|
-// 滚动到指定章节(通过标题文本匹配)
|
|
|
+// 滚动到指定章节(通过标题元素匹配)
|
|
|
function scrollToHeading(item) {
|
|
|
- // 优先通过 anchorId 查找
|
|
|
- if (item.anchorId) {
|
|
|
- const anchorEl = document.querySelector(`[data-element-id="${item.anchorId}"]`)
|
|
|
- if (anchorEl) {
|
|
|
- anchorEl.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
|
- highlightElement(anchorEl)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 通过标题文本在文档内容中查找
|
|
|
const titleText = item.title || item.text
|
|
|
if (!titleText) return
|
|
|
|
|
|
- // 在文档内容区域中查找匹配的文本
|
|
|
+ // 在文档内容区域中查找标题元素 (h1, h2, h3, h4, h5, h6)
|
|
|
const editorContent = document.querySelector('.editor-content')
|
|
|
if (!editorContent) return
|
|
|
|
|
|
- // 查找包含该标题文本的元素
|
|
|
- const walker = document.createTreeWalker(
|
|
|
- editorContent,
|
|
|
- NodeFilter.SHOW_TEXT,
|
|
|
- null,
|
|
|
- false
|
|
|
- )
|
|
|
+ // 查找所有标题元素
|
|
|
+ const headings = editorContent.querySelectorAll('h1, h2, h3, h4, h5, h6')
|
|
|
|
|
|
- let node
|
|
|
- while ((node = walker.nextNode())) {
|
|
|
- if (node.textContent && node.textContent.includes(titleText)) {
|
|
|
- const parent = node.parentElement
|
|
|
- if (parent) {
|
|
|
- parent.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
|
- highlightElement(parent)
|
|
|
- return
|
|
|
- }
|
|
|
+ for (const heading of headings) {
|
|
|
+ // 获取标题的纯文本内容(去除空格比较)
|
|
|
+ const headingText = heading.textContent?.trim()
|
|
|
+ if (headingText && headingText === titleText.trim()) {
|
|
|
+ // 滚动到标题元素
|
|
|
+ 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())) {
|
|
|
+ heading.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
|
+ highlightElement(heading)
|
|
|
+ return
|
|
|
}
|
|
|
}
|
|
|
|