fix: 后端highlight

This commit is contained in:
Tim
2025-09-28 14:55:56 +08:00
parent 8869121bcb
commit 2977d2898f
6 changed files with 199 additions and 48 deletions

View File

@@ -26,9 +26,20 @@
<div class="search-option-item">
<component :is="iconMap[option.type]" class="result-icon" />
<div class="result-body">
<div class="result-main" v-html="highlight(option.text)"></div>
<div v-if="option.subText" class="result-sub" v-html="highlight(option.subText)"></div>
<div v-if="option.extra" class="result-extra" v-html="highlight(option.extra)"></div>
<div
class="result-main"
v-html="renderHighlight(option.highlightedText, option.text)"
></div>
<div
v-if="option.subText"
class="result-sub"
v-html="renderHighlight(option.highlightedSubText, option.subText)"
></div>
<div
v-if="option.extra"
class="result-extra"
v-html="renderHighlight(option.highlightedExtra, option.extra)"
></div>
</div>
</div>
</template>
@@ -70,16 +81,30 @@ const fetchResults = async (kw) => {
subText: r.subText,
extra: r.extra,
postId: r.postId,
highlightedText: r.highlightedText,
highlightedSubText: r.highlightedSubText,
highlightedExtra: r.highlightedExtra,
}))
return results.value
}
const highlight = (text) => {
text = stripMarkdown(text)
if (!keyword.value) return text
const reg = new RegExp(keyword.value, 'gi')
const res = text.replace(reg, (m) => `<span class="highlight">${m}</span>`)
return res
const escapeHtml = (value = '') =>
String(value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
const renderHighlight = (highlighted, fallback) => {
if (highlighted) {
return highlighted
}
const plain = stripMarkdown(fallback || '')
if (!plain) {
return ''
}
return escapeHtml(plain)
}
const iconMap = {
@@ -168,7 +193,7 @@ defineExpose({
padding: 10px 20px;
}
:deep(.highlight) {
:deep(mark) {
color: var(--primary-color);
}

View File

@@ -32,11 +32,14 @@
:disable-link="true"
/>
<div class="result-body">
<div class="result-main" v-html="highlight(option.username)"></div>
<div
class="result-main"
v-html="renderHighlight(option.highlightedUsername, option.username)"
></div>
<div
v-if="option.introduction"
class="result-sub"
v-html="highlight(option.introduction)"
v-html="renderHighlight(option.highlightedIntroduction, option.introduction)"
></div>
</div>
</div>
@@ -79,15 +82,29 @@ const fetchResults = async (kw) => {
username: u.username,
avatar: u.avatar,
introduction: u.introduction,
highlightedUsername: u.highlightedText,
highlightedIntroduction: u.highlightedSubText || u.highlightedExtra,
}))
return results.value
}
const highlight = (text) => {
text = stripMarkdown(text || '')
if (!keyword.value) return text
const reg = new RegExp(keyword.value, 'gi')
return text.replace(reg, (m) => `<span class="highlight">${m}</span>`)
const escapeHtml = (value = '') =>
String(value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
const renderHighlight = (highlighted, fallback) => {
if (highlighted) {
return highlighted
}
const plain = stripMarkdown(fallback || '')
if (!plain) {
return ''
}
return escapeHtml(plain)
}
watch(selected, async (val) => {
@@ -170,7 +187,7 @@ defineExpose({
padding: 10px 20px;
}
:deep(.highlight) {
:deep(mark) {
color: var(--primary-color);
}