【转】前端预览 PDF 文件(使用PDFJS)

转:https://segmentfault.com/a/1190000040331855

哈喽大家好啊。前半年还挺忙的,一直也没有发文章,有老哥想我了嘛。这两天发现老有人私信问我 PDF 相关的内容。

那么好,为了我能安心摸鱼,我准备出一篇文章来介绍一下如何使用 PDFJS 。

PDF.js 是什么?

PDF.js 由 Mozilla 提供支持。目标是创建一个通用的、基于 Web 标准的平台,用于解析和呈现 PDF。

预览 PDF

使用 iframe、embed、新窗口打开

测试地址,方案比较简单,属于看天吃饭,全靠浏览器爸爸赏。

使用方式

<embed src="https://www.lilnong.top/static/pdf/B-4-RxJS%E5%9C%A8React%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8-%E9%BE%99%E9%80%B8%E6%A5%A0_.pdf">
<iframe src="https://www.lilnong.top/static/pdf/B-4-RxJS%E5%9C%A8React%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8-%E9%BE%99%E9%80%B8%E6%A5%A0_.pdf"></iframe>

测试结果

浏览器兼容性配图
Chrome(PC)(Mac) 支持 image.png
safari(PC)(Mac) 支持 image.png
Firefox(PC)(Mac) 支持 image.png
Firefox(PC)(Windows) 支持 image.png
Edge(PC)(Windows) 支持 image.png
IE(PC)(Windows) 不支持 image.png
微信(Android)(vivo x27) 不支持 image.png
Chrome(Android)(vivo x27) 不支持 image.png
QQ浏览器(Android)(vivo x27) 不支持 image.png

优点:简单,支持大部分 PC 浏览器(IE 不支持)。跨域资源同样可以(无需 cors)
缺点:不支持移动端浏览器,不支持 IE 等低版本浏览器。样式无法自定义。

pdfjs-view

测试地址,方案兼容性比较好,需要资源同域 或者 cors跨域,可以自定义样式。

使用方式

  1. 自己部署一个 pdfjs-view。 (推荐,更稳定)

    1. 下载项目,然后项目分为两个版本/web/viewer-1.html 和 /legacy/web/viewer.html 。legacy 支持低版本浏览器,使用 es5 编写,讲道理采用这个方案,你肯定也是为了兼容所有浏览器。(没有的话,就 gulp generic-legacy 生成一份)
    2. 然后将相关内容复制到你的目录,上传 FTP。
    3. 本质来讲他就是一个 HTML 文件,所以你可以针对他进行一些修改,比如说主题颜色、隐藏下载按钮等等。
  2. 使用 CDN 或者官方提供的 pdfjs-view。(不推荐,不稳定,异常CORS)

    1. https://mozilla.github.io/pdf.js/legacy/web/viewer.html
    2. https://mozilla.github.io/pdf.js/web/viewer.html
<iframe src="https://www.lilnong.top/static/project?file=https://www.lilnong.top/static/pdf/B-4-RxJS%E5%9C%A8React%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8-%E9%BE%99%E9%80%B8%E6%A5%A0_.pdf"></iframe>
<iframe src="https://www.lilnong.top/static/project/pdfjs-es5-2.5.207/web/viewer-1.html?file=https://www.lilnong.top/static/pdf/B-4-RxJS%E5%9C%A8React%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8-%E9%BE%99%E9%80%B8%E6%A5%A0_.pdf"></iframe>

测试结果

浏览器兼容性兼容性 ES5 版本配图
Chrome(PC)(Mac) 支持 支持 image.png
safari(PC)(Mac) 支持 支持 image.png
Firefox(PC)(Mac) 支持 支持 image.png
Firefox(PC)(Windows) 支持 支持 image.png
Edge(PC)(Windows) 支持 支持 image.png
IE(PC)(Windows) 不支持 支持 image.png
微信(Android)(vivo x27) 支持 支持 image.png
Chrome(Android)(vivo x27) 支持 支持 image.png
QQ浏览器(Android)(vivo x27) 支持 支持 image.png

同上,可以看到 IE 都支持,移动端也 OK。

优点:支持大部分浏览器(PC、M端都支持)。跨域资源需要 cors。样式可以自定义。
缺点:需要部署一个 view。

pdfjs-canvas

测试地址,方案比较复杂,需要自己实现一套预览配套的内容(分页、放大缩小)。

使用方式

(function() {
    let el = document.getElementById('canvasWrap');
    if (!el) {
        el = document.createElement('div')
        el.id = 'canvasWrap'
        document.body.appendChild(el)
    }
    el.innerHTML = ''
    let winW = document.documentElement.clientWidth
    // 加载 pdf 资源
    let loadingTask = pdfjsLib.getDocument('https://www.lilnong.top/static/pdf/B-4-RxJS%E5%9C%A8React%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8-%E9%BE%99%E9%80%B8%E6%A5%A0_.pdf')
    // PDF 加载完成的回调。
    loadingTask.promise.then(function(pdf) {
        console.log('pdf', pdf)
        // 可以获取到总页数。
        let pageNum = pdf.numPages
        var _pageNum = 1;
        var renderPageToCanvas = function(pageNum, auto=false) {
            // 获取其中的一个页面
            pdf.getPage(pageNum).then(function(page) {
                // you can now use *page* here
                _pageNum = pageNum
                // 获取原始大小的数据
                var viewport = page.getViewport({
                    scale: 1,
                });
                var scale = (500 / viewport.width).toFixed(2)
                viewport = page.getViewport({
                    scale: scale
                });
                var canvas = document.createElement('canvas');
                el.appendChild(canvas)
                var context = canvas.getContext('2d');
                canvas.height = viewport.height;
                canvas.width = viewport.width;
                
                // 创建了一个canvas画板用来存放
                var renderContext = {
                    canvasContext: context,
                    viewport: viewport
                };
                page.render(renderContext);
                if (auto)
                    renderPageToCanvas(pageNum + 1, auto);
            });
        }
        renderPageToCanvas(_pageNum, true);
        canvasPrev.onclick = function() {
            renderPageToCanvas(Math.max(_pageNum - 1, 1));
        }
        canvasNext.onclick = function() {
            renderPageToCanvas(Math.min(_pageNum + 1, pdf.numPages));
        }
    }, function(reason) {
        console.error(reason)
    })

}
)()

测试结果

浏览器兼容性配图
Chrome(PC)(Mac) 支持 image.png
safari(PC)(Mac) 支持 image.png
Firefox(PC)(Mac) 支持 image.png
Firefox(PC)(Windows) 支持 image.png
Edge(PC)(Windows) 支持 image.png
IE(PC)(Windows) 不支持 image.png
微信(Android)(vivo x27) 支持 image.png
Chrome(Android)(vivo x27) 支持 image.png
QQ浏览器(Android)(vivo x27) 支持 image.png

兼容性也还可以,需要依赖canvas。

下载 PDF

  1. 下载头
  2. 直接打开

    1. 如果浏览器不支持解析 PDF 那么可以触发下载。
    2. 如果浏览器支持解析 PDF,那么会变成预览。
    1. 这个时候我们可以给 a 标签加上 download 来触发下载。(需要同域)

总结一下

通过上面的内容我们可以实现前端预览PDF功能了,我们来总结一下各个方案的特征。

方案移动端PC端(高版本浏览器)PC端(IE、低版本浏览器)跨域复制内容自定义样式(分页、下载等等)
iframe ❌(平台不支持) ❌(平台不支持)
embed ❌(平台不支持) ❌(平台不支持) ✅(CORS)
pdfjs-view ❌(ES6 新特性) ✅(CORS) ✅(基于原有基础去修改)
pdfjs-view-es5 ✅(CORS) ✅(基于原有基础去修改)
pdfjs-canvas ❌(canvas) ✅(CORS) ❌(canvas) ✅(完全需要自己去实现一整套操作)

好了,还需要什么内容欢迎留言啊。我给更新到里面。

posted @ 2021-09-02 15:47  居无常  阅读(544)  评论(0编辑  收藏  举报