低成本·无任何依赖·实现大文件pdf预览功能-带下载进度

经常做pdf预览的小伙伴都知道,如 pdfjs,pdfjs-dist,react-pdf等等,各种库,但是其实就是为了预览一下pdf内容。
而且pdfjs-dist还会依赖node-pre-gyp,做前端的都知道,这个gpy是有多恶心。

好了,为了不用任何库,就可以预览pdf,你可以如下操作:

1. 新窗口打开或将pdf地址放在iframe 的src里预览

写法如下:

这么做有一个问题,如果pdf的地址请求头是application/octet-stream的话,pdf会被下载下来,无法预览。

2. 使用ajax获取pdf之后,在iframe里预览。

import { useEffect, useState } from 'react';

const App = () => {
    const [errorMsg, setErrorMsg] = useState('')
    const [pdfBlobUrl, setPdfBlobUrl] = useState('')
    const [loading, setLoading] = useState(false)
    const [progress, setProgress] = useState(0)

    const fetchPdfWithXHR = () => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://example.com/test.pdf', true); // 替换为实际的接口地址

        // 设置请求头(根据需要)
        xhr.setRequestHeader('Content-Type', 'application/json');

        // 指定返回类型为 Blob
        xhr.responseType = 'blob';

        // 请求成功处理
        xhr.onload = () => {
            // 由于带进度下载的请求,status是206,不是200,所这里做一下处理。
            if (xhr.status>=200 && xhr.status<300) {
                // 将 Blob 数据生成 URL
                const blob = new Blob([xhr.response], { type: 'application/pdf' });
                const url = URL.createObjectURL(blob);
                setPdfBlobUrl(url);
            } else {
                setErrorMsg('Failed to fetch PDF:' + xhr.status + xhr.statusText);
            }
        };

        // 下载进度监听器
        xhr.onprogress = (event) => {
            if (event.lengthComputable) {
                const v = loaded / total * 100
                setProgress(Math.floor(v))
            }
        }

        // 错误处理
        xhr.onerror = () => {
            console.error('Network error while fetching PDF.');
        };

        // 发送请求
        const requestBody = JSON.stringify({
            // 替换为实际的请求参数
            token: '',
        });
        xhr.send(requestBody);
    };

    useEffect(() => {
        fetchPdfWithXHR();
    }, []);

    return loading ? 
Loading PDF {progress}%...
: pdfBlobUrl ? (