pdf.js 自定义关键词高亮及一键搜索 您所在的位置:网站首页 pdf文件怎么查找关键字 pdf.js 自定义关键词高亮及一键搜索

pdf.js 自定义关键词高亮及一键搜索

2024-06-06 19:32| 来源: 网络整理| 查看: 265

由于目前实现在公司内部的后台项目,故不展示截图,可根据代码自行实践查看效果。

背景

之前公司内部一个后台系统,需要在前端展示 pdf 文件,并且需要在半屏展示,另外半屏需要展示其他内容。

一开始是直接使用 iframe 进行打开,后来由于某些 pdf 的文字编码问题,导致 Chrome 无法正常展示文字,后来发现 Mozilla 的 pdf.js 可以展示,于是将 iframe 打开的页面替换成 pdf.js 的 html 来展示 pdf 文件。

后来为了进一步提效,有了几个需求:

后台传来数据和 pdf 文件地址,前端需要在 pdf 文件中把所有关键词进行高亮标记; 后台传来的数据每一个词都需要点击一键搜索,需要 pdf 文件自动跳转到关键词并高亮标记。

于是就开始研究如何在使用 iframe 嵌入的 pdf.js 页面中进行实现。

实现 展示指定 pdf 文件

这个虽然花费了几个小时,但是并没有什么技术含量。在我翻了它的 viewer.js 文件后发现,其实只需要传一个查询参数即可。形如:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import {defineProps,computed } from 'vue'; const props = defineProps(); const iframeSrc = computed(() => { if (props.pdfUrl){ return `${window.location.origin}/pdfViewer/web/viewer.html?pdf=${props.pdfUrl}`; } return ''; });

这个地址是我项目引入 pdf.js 的文件路径,其实就是打开 pdf.js 的 html 文件,然后传入一个查询参数 pdf,值为 pdf 文件的地址即可。

高亮关键词

首先我看了一下 pdf.js 嵌入之后的 DOM,发现他将每一页都分了两部分,一部分是 canvas,一部分是 div。

canvas 主要是为了实现画笔之类的功能,因为目前我从后台能拿到的只有文字,其他信息都没有,所以应该是用不上了。

div 中的内容就是 pdf 文件的文字内容,被各种标签包围着赋予样式,类似代码块的 DOM,这种的话我们应该可以给对应的 html 元素添加样式实现高亮。

思路有了,那就开干吧!

拿到 iframe 的 DOM

想要操作 DOM,那肯定需要先获取到 DOM 对象,那么我们就需要先拿到 iframe 的 DOM,再从里面拿到需要的 pdf 文件的根节点,后续就可以遍历根节点的所有页面元素来实现高亮了。

1 2 // 示例使用 ts 获取,如果在 vue/react 中,可以使用 ref,并相应使用 value 和 current const iframe = document.querySelector('#iframeId');

获取到 iframe 的 DOM 之后,就可以拿到 iframe 的 window 和 document 了。

拿到 iframe 的 document 对象

在获取 iframe 的 document 之前先判断 pdf.js 的页面 js 是否已执行完成,否则 pdf 可能会出错。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 这里我扩展了一下 pdf.js 的 window 对象,因为我需要使用到里面的属性 type IframeWindow = { PDFViewerApplication : { eventBus : { dispatch : (type : string, data : any) => void; }; pagesCount : number; }; } & Window; // 检查 iframe 是否加载完成,这里我是使用 iframe 的 windows 上是否已经有了 pagesCount 属性来判断 const window = iframe.contentWindow as IframeWindow | null; if (!window?.PDFViewerApplication?.pagesCount) return; iframeWindow = iframe.value!.contentWindow as IframeWindow; console.log('PDF 总页数', iframeWindow.PDFViewerApplication.pagesCount); // 获取 iframe 的 document const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

这个 iframeDoc 就是 pdf 的 iframe 的 document 了,我们从里面拿出所有的 .page 元素,这个元素就是每一页的根节点了。

拿到 pdf 所有的 .page 元素进行高亮

在这里我获取的方式是定时轮询去获取,从 iframe 的 window 中拿到文件总页数,然后使用下面拿到的元素个数去对比,如果相等则说明已经拿到了所有的元素,这时候才开始进行操作。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const pages = iframeDoc.querySelectorAll('.page'); // 这里之所以使用 setInterval,是因为 pdf.js 是动态加载页面内容的 // .page 元素里的内容会动态增删,所以如果只执行一次,后面的页面都会没有高亮效果 const highlightPDF = setInterval(() => { if (!pages) return; // 对后台拿到的关键词数组进行去重,如果没有关键词的就不进行遍历操作了 const keywords = [...new Set(props.keywords)]; if ((keywords.length === 1 && !props.keywords[0]) || !keywords.length) return; // 遍历 .page 元素进行高亮 for (let i = 0; i { // 取出 .page 元素中的 .textLayer 元素,这个元素就是 pdf 文件中的文字内容 const textLayer = dom.querySelector('.textLayer'); if (!textLayer) return; // 这里我使用了正则去除掉所有的特殊符号,因为中英文符号可能导致不匹配 for (let node of textLayer.children) { if (node.textContent) { const result = props.keywords.filter(keyword => node.textContent!.replace(pattern, '').includes(keyword.replace(pattern, '')) ); node.style.backgroundColor = !result.length ? 'transparent' : 'red'; } } };

OK!大功告成。这时候我们传入关键词数组就可以在 pdf 文件中看到高亮的关键词了。

这里做得稍微比较粗糙,我直接将匹配到关键词的整个元素进行高亮,会导致高亮整句话,实际上可以给该关键词使用特殊标签包裹,然后给该标签添加样式,这样可以更精确地控制高亮的范围。由于内部系统并不是特别重要,所以就没有做这个优化了。

一键搜索

另一个需求是上面后台传来的关键词需要在页面右侧展示,并且点击一键在左侧的 iframe 里的 pdf 中跳转定位。

这个我使用的就是 pdf.js 自身的搜索功能,去翻一翻它的 viewer.js 源码,发现了它的搜索调用的方法如下:

1 2 3 4 5 6 7 8 9 10 11 12 // 这个 PDFViewerApplication 是 pdf.js 注入 window 对象的,这也是前面我扩展了 iframe 的 window 的类型的原因 PDFViewerApplication.eventBus.dispatch('find', { source: evt.source, type: '', query: evt.query, phraseSearch: evt.phraseSearch, caseSensitive: false, entireWord: false, highlightAll: true, findPrevious: false, matchDiacritics: true, });

注意上面的 window 指的是 iframe 的 window,并不是当前页面的 window,所以我们需要在 iframe 的 window 上调用这个方法。

上面这个方法调用的时候会使用 iframe 中 pdf 的搜索 input 的 value 来进行搜索,所以我们需要在 iframe 中找到这个 input,然后将我们的关键词赋值给它,然后调用上面的方法即可。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // 获取 iframe 的 window const iframeWindow = iframe.contentWindow as IframeWindow | null; if (!iframeWindow) return; // 获取 iframe 中的搜索 input const searchInput = iframeWindow.document.querySelector('#findInput') as HTMLInputElement | null; // 定义搜索方法 const searchKeyword = (keyword: string) => { if (!iframeWindow || !searchInput) return; // 将关键词赋值给 input searchInput!.value = keyword; // 调用 pdf.js 的搜索方法 iframeWindow.PDFViewerApplication.eventBus.dispatch('find', { type: '', query: keyword, highlightAll: true, }); };

由于这里我不需要配置忽略大小写,符号,整词等,所以只配置了高亮属性为 true,如果你需要的话可以在上面的方法中传入更多配置。

OK!这样我们就可以在页面中点击关键词时候调用上面的 searchKeyword 方法,就可以在 pdf 中直接跳转并高亮对应的关键词了。

总结

这篇文章主要是讲了一下我在项目中遇到的一个需求,通过这个需求,我学习了一下如何使用 pdf.js 来实现 pdf 的预览和高亮,以及如何使用 pdf.js 的搜索功能来实现一键搜索。

发现了 iframe 使用的其他一些小技巧,比如如何获取 iframe 的 window,以及如何获取 iframe 的 document 等。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有