提交 59089e47 authored 作者: 朱政's avatar 朱政

feat:智库原文搜索高亮开发

上级 945bd0af
流水线 #593 已失败 于阶段
in 52 秒
...@@ -326,34 +326,39 @@ export default { ...@@ -326,34 +326,39 @@ export default {
} }
} }
if (matchList.value.length > 0) jumpTo(0); if (matchList.value.length > 0) {
// 先把所有命中都标黄,再把“当前命中”改成蓝底
renderAllHighlights();
jumpTo(0);
}
}; };
// 跳转到第 N 个匹配项 const setActiveHighlight = (idx) => {
const jumpTo = (idx) => { const all = document.querySelectorAll('.highlight-rect[data-match-idx]');
if (idx < 0 || idx >= matchList.value.length) return; all.forEach((el) => {
matchIdx.value = idx; const isActive = Number(el.getAttribute('data-match-idx')) === Number(idx);
const m = matchList.value[idx]; if (isActive) {
if (m?.fallback) { el.classList.add('highlight-rect--active');
// 兜底命中:只定位页码,不做高亮 } else {
goToPage(m.pageNum); el.classList.remove('highlight-rect--active');
return;
} }
const firstSeg = m?.segments?.[0]; });
const el = firstSeg?.el; };
if (!el) return;
const renderAllHighlights = () => {
clearHighlights(); clearHighlights();
const list = Array.isArray(matchList.value) ? matchList.value : [];
list.forEach((m, idx) => {
if (!m || m.fallback) return;
const layer = overlayMap[m.pageNum]; const layer = overlayMap[m.pageNum];
if (!layer) return; if (!layer) return;
const pageWrap = layer.closest('.page-wrap'); const pageWrap = layer.closest('.page-wrap');
const container = (pageWrap || layer);
// 用 Range 精确计算“子串”在页面上的矩形位置,再画黄色块(支持跨 span) const containerRect = container.getBoundingClientRect();
const containerRect = (pageWrap || layer).getBoundingClientRect();
const segs = Array.isArray(m?.segments) ? m.segments : []; const segs = Array.isArray(m?.segments) ? m.segments : [];
for (const seg of segs) { for (const seg of segs) {
const segEl = seg?.el; const segEl = seg?.el;
if (!segEl) continue; if (!segEl) continue;
const textNode = segEl.firstChild; const textNode = segEl.firstChild;
if (!textNode || textNode.nodeType !== Node.TEXT_NODE) continue; if (!textNode || textNode.nodeType !== Node.TEXT_NODE) continue;
try { try {
...@@ -365,25 +370,26 @@ export default { ...@@ -365,25 +370,26 @@ export default {
rectList.forEach(r => { rectList.forEach(r => {
const mark = document.createElement('div'); const mark = document.createElement('div');
mark.className = 'highlight-rect'; mark.className = 'highlight-rect';
mark.setAttribute('data-match-idx', String(idx));
mark.style.zIndex = '5'; mark.style.zIndex = '5';
mark.style.left = (r.left - containerRect.left) + 'px'; mark.style.left = (r.left - containerRect.left) + 'px';
mark.style.top = (r.top - containerRect.top) + 'px'; mark.style.top = (r.top - containerRect.top) + 'px';
mark.style.width = r.width + 'px'; mark.style.width = r.width + 'px';
mark.style.height = r.height + 'px'; mark.style.height = r.height + 'px';
(pageWrap || layer).appendChild(mark); container.appendChild(mark);
}); });
} else { } else {
// Range 兜底为空时:用 span 自身的矩形画块(精度低,但尽量可见)
const r = segEl.getBoundingClientRect(); const r = segEl.getBoundingClientRect();
if (r.width > 0 && r.height > 0) { if (r.width > 0 && r.height > 0) {
const mark = document.createElement('div'); const mark = document.createElement('div');
mark.className = 'highlight-rect'; mark.className = 'highlight-rect';
mark.setAttribute('data-match-idx', String(idx));
mark.style.zIndex = '5'; mark.style.zIndex = '5';
mark.style.left = (r.left - containerRect.left) + 'px'; mark.style.left = (r.left - containerRect.left) + 'px';
mark.style.top = (r.top - containerRect.top) + 'px'; mark.style.top = (r.top - containerRect.top) + 'px';
mark.style.width = r.width + 'px'; mark.style.width = r.width + 'px';
mark.style.height = r.height + 'px'; mark.style.height = r.height + 'px';
(pageWrap || layer).appendChild(mark); container.appendChild(mark);
} }
} }
range.detach?.(); range.detach?.();
...@@ -391,6 +397,24 @@ export default { ...@@ -391,6 +397,24 @@ export default {
// ignore // ignore
} }
} }
});
setActiveHighlight(matchIdx.value);
};
// 跳转到第 N 个匹配项
const jumpTo = (idx) => {
if (idx < 0 || idx >= matchList.value.length) return;
matchIdx.value = idx;
const m = matchList.value[idx];
if (m?.fallback) {
// 兜底命中:只定位页码,不做高亮
goToPage(m.pageNum);
return;
}
const firstSeg = m?.segments?.[0];
const el = firstSeg?.el;
if (!el) return;
setActiveHighlight(idx);
// 优先只滚动右侧 report-box,避免触发整页滚动导致 header 遮挡 // 优先只滚动右侧 report-box,避免触发整页滚动导致 header 遮挡
const container = el.closest('.report-box'); const container = el.closest('.report-box');
...@@ -510,6 +534,10 @@ canvas { ...@@ -510,6 +534,10 @@ canvas {
z-index: 5; z-index: 5;
} }
.textLayer :deep(.highlight-rect--active) {
background: rgb(184, 222, 254);
}
.page-wrap :deep(.highlight-rect) { .page-wrap :deep(.highlight-rect) {
position: absolute; position: absolute;
background: #ff0; background: #ff0;
...@@ -519,6 +547,10 @@ canvas { ...@@ -519,6 +547,10 @@ canvas {
z-index: 3; z-index: 3;
} }
.page-wrap :deep(.highlight-rect--active) {
background: rgb(184, 222, 254);
}
.loading { .loading {
position: absolute; position: absolute;
top: 50%; top: 50%;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论