word 搜索优化

This commit is contained in:
cwchen 2025-11-12 16:09:23 +08:00
parent 48dd413f87
commit 5be02d46fd
1 changed files with 54 additions and 13 deletions

View File

@ -176,6 +176,33 @@ export default {
return (element.textContent || '').trim() return (element.textContent || '').trim()
}, },
getSearchableTextContent(element) {
if (!element) return ''
let text = ''
const walker = document.createTreeWalker(
element,
NodeFilter.SHOW_TEXT,
{
acceptNode: (node) => {
const parent = node.parentElement
if (!parent) return NodeFilter.FILTER_REJECT
const tagName = parent.tagName ? parent.tagName.toLowerCase() : ''
if (tagName === 'mark' || tagName === 'script' || tagName === 'style' || tagName === 'noscript') {
return NodeFilter.FILTER_REJECT
}
return NodeFilter.FILTER_ACCEPT
}
}
)
let node
while ((node = walker.nextNode())) {
if (node.textContent) {
text += node.textContent
}
}
return text
},
prepareSearchSegments(forceReset = false) { prepareSearchSegments(forceReset = false) {
if (!this.docRendered) { if (!this.docRendered) {
if (forceReset) { if (forceReset) {
@ -270,7 +297,7 @@ export default {
highlightTextInNode(node, pattern, results, segmentIndex, parentElement, markIndexRef) { highlightTextInNode(node, pattern, results, segmentIndex, parentElement, markIndexRef) {
if (node.nodeType === Node.TEXT_NODE) { if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent const text = node.textContent
if (!text || !text.trim()) return if (!text) return
pattern.lastIndex = 0 pattern.lastIndex = 0
const textMatches = [] const textMatches = []
@ -355,17 +382,9 @@ export default {
const results = [] const results = []
let totalTextMatches = 0 let totalTextMatches = 0
const segmentMatchCounts = []
this.searchSegments.forEach((el, segmentIndex) => { this.searchSegments.forEach((el, segmentIndex) => {
const originalText = el.dataset.originalText
if (typeof originalText === 'undefined' || !originalText) return
pattern.lastIndex = 0
const textMatchCount = (originalText.match(pattern) || []).length
if (textMatchCount === 0) return
totalTextMatches += textMatchCount
const originalHtml = el.dataset.originalHtml const originalHtml = el.dataset.originalHtml
if (typeof originalHtml === 'undefined') return if (typeof originalHtml === 'undefined') return
@ -373,25 +392,47 @@ export default {
el.innerHTML = cleanHtml el.innerHTML = cleanHtml
el.dataset.originalHtml = cleanHtml el.dataset.originalHtml = cleanHtml
const searchableText = this.getSearchableTextContent(el)
if (!searchableText) return
pattern.lastIndex = 0
const textMatchCount = (searchableText.match(pattern) || []).length
if (textMatchCount === 0) return
totalTextMatches += textMatchCount
const existingMarks = el.querySelectorAll('mark') const existingMarks = el.querySelectorAll('mark')
if (existingMarks.length > 0) { if (existingMarks.length > 0) {
console.warn(`Segment ${segmentIndex} still has ${existingMarks.length} mark tags after cleaning`) console.warn(`Segment ${segmentIndex} still has ${existingMarks.length} mark tags after cleaning`)
} }
const markIndexRef = { value: 0 } const markIndexRef = { value: 0 }
const beforeHighlightText = this.getSearchableTextContent(el)
const children = Array.from(el.childNodes) const children = Array.from(el.childNodes)
children.forEach(child => { children.forEach(child => {
this.highlightTextInNode(child, pattern, results, segmentIndex, el, markIndexRef) this.highlightTextInNode(child, pattern, results, segmentIndex, el, markIndexRef)
}) })
const createdMarks = el.querySelectorAll('mark.search-highlight') const createdMarks = el.querySelectorAll('mark.search-highlight')
if (createdMarks.length !== textMatchCount) { const actualCount = createdMarks.length
console.warn(`Segment ${segmentIndex}: expected ${textMatchCount} marks, created ${createdMarks.length}`) const afterHighlightText = this.getSearchableTextContent(el)
segmentMatchCounts.push({
segmentIndex,
expected: textMatchCount,
actual: actualCount,
searchableTextLength: searchableText.length,
beforeHighlightLength: beforeHighlightText.length,
afterHighlightLength: afterHighlightText.length
})
if (actualCount !== textMatchCount) {
console.warn(`Segment ${segmentIndex}: expected ${textMatchCount} marks, created ${actualCount}. Text: "${searchableText.substring(0, 100)}..."`)
} }
}) })
if (results.length !== totalTextMatches) { if (results.length !== totalTextMatches) {
console.warn(`Total matches mismatch: expected ${totalTextMatches}, got ${results.length}`) console.warn(`Total matches mismatch: expected ${totalTextMatches}, got ${results.length}`, segmentMatchCounts)
} }
this.searchResults = results this.searchResults = results