记录技术成长,奔向未来!

如何实现编辑器插入PDF功能,前台实现翻页呢?

摘要: 我们来实现一个独立的插入 PDF 文件功能,支持前台以类似 PDF 阅读器的方式左右翻页预览。需要两个部分: 编辑器端:新增“插入 PDF”按钮,上传 PDF 文件或输入 URL,生成一个特殊的占位符(例如 <div class="pdf-viewer" data-pdf="url"></div>)。 前台展示:使用 PDF.js 库渲染 PDF,支持翻页、缩放等。 由于 PDF.js 是 Mozilla 开源项目,稳定且功能强大,我们将它集成到前台文章页。


一、编辑器端:插入 PDF 功能

1.1 在 createToolbar 中添加按钮

找到插入分组(图片、视频、链接、表格等附近),增加:

javascript
复制
下载
{ custom: () => this.insertPDF(), icon: '📄', title: '插入PDF' }

1.2 实现 insertPDF 方法

javascript
复制
下载
insertPDF() {
    const choice = confirm('点击"确定"上传本地PDF,点击"取消"输入PDF链接');
    if (choice) {
        this.uploadLocalPDF();
    } else {
        this.embedPDFUrl();
    }
}

uploadLocalPDF() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'application/pdf';
    input.onchange = async () => {
        const file = input.files[0];
        if (!file) return;
        const placeholder = `📄 PDF上传中: ${file.name}...`;
        document.execCommand('insertText', false, placeholder);
        const formData = new FormData();
        formData.append('attachment', file);
        // 使用附件上传接口,但限制 PDF 类型(您可能需要单独的上传接口或修改现有接口)
        // 这里假设 /admin/upload_attachment.php 支持 PDF
        const res = await fetch(this.attachmentUploadUrl, { method: 'POST', body: formData });
        const data = await res.json();
        if (data.url) {
            const pdfHtml = `<div class="pdf-viewer" data-pdf="${data.url}" style="margin:10px 0; border:1px solid #ddd; padding:10px; background:#f9f9f9; text-align:center;">📄 PDF文件: <a href="${data.url}" target="_blank">${file.name}</a> <span style="color:#1abc9c;">(点击右侧按钮可在线预览)</span></div>`;
            this.editorDiv.innerHTML = this.editorDiv.innerHTML.replace(placeholder, pdfHtml);
        } else {
            alert('上传失败:' + (data.error || '未知错误'));
            this.editorDiv.innerHTML = this.editorDiv.innerHTML.replace(placeholder, '');
        }
        this.syncToTextarea();
    };
    input.click();
}

embedPDFUrl() {
    const url = prompt('请输入PDF文件链接(URL):', 'https://');
    if (!url) return;
    const pdfHtml = `<div class="pdf-viewer" data-pdf="${this.escapeHtml(url)}" style="margin:10px 0; border:1px solid #ddd; padding:10px; background:#f9f9f9; text-align:center;">📄 PDF文件: <a href="${this.escapeHtml(url)}" target="_blank">点击下载</a> <span style="color:#1abc9c;">(加载中...)</span></div>`;
    document.execCommand('insertHTML', false, pdfHtml);
    this.syncToTextarea();
}

注意:您需要确保上传接口(upload_attachment.php)支持 PDF 文件(已经支持,因为之前 allowed 包含 application/pdf)。

二、前台使用 PDF.js 渲染 PDF,支持左右翻页

2.1 下载 PDF.js 并放置到您的项目中

从 https://mozilla.github.io/pdf.js/ 下载最新稳定版,解压后将 build/ 目录下的 pdf.js 和 pdf.worker.js 以及 web/ 下的 viewer.html 等资源放到您的 assets/js/pdfjs/ 目录。

但为了简化,我们可以在前台直接动态加载 PDF.js 的 CDN,并自定义一个轻量级查看器。

2.2 在前台 article.php 或 header.php 中添加 PDF.js 的加载(仅当页面包含 PDF 时加载)

在 article.php 的文章内容输出之后,添加以下脚本:

html
复制
下载
运行
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js"></script>
<script>
    // 设置 worker
    pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
    
    // 为所有 .pdf-viewer 元素渲染 PDF 预览
    document.querySelectorAll('.pdf-viewer').forEach(container => {
        const pdfUrl = container.getAttribute('data-pdf');
        if (!pdfUrl) return;
        
        // 创建画布和翻页按钮
        container.innerHTML = ''; // 清空原有内容
        container.style.cssText = 'position:relative; background:#f0f0f0; border:1px solid #ccc; border-radius:8px; padding:10px; text-align:center;';
        
        const canvas = document.createElement('canvas');
        canvas.style.maxWidth = '100%';
        canvas.style.height = 'auto';
        container.appendChild(canvas);
        
        const controls = document.createElement('div');
        controls.style.marginTop = '10px';
        controls.innerHTML = `
            <button class="pdf-prev" disabled>◀ 上一页</button>
            <span class="pdf-page-info">第 0 / 0 页</span>
            <button class="pdf-next" disabled>下一页 ▶</button>
            <button class="pdf-download">⬇️ 下载</button>
        `;
        container.appendChild(controls);
        
        let pdfDoc = null;
        let currentPage = 1;
        let totalPages = 0;
        
        const renderPage = (num) => {
            pdfDoc.getPage(num).then(page => {
                const viewport = page.getViewport({ scale: 1.5 });
                canvas.width = viewport.width;
                canvas.height = viewport.height;
                const ctx = canvas.getContext('2d');
                page.render({ canvasContext: ctx, viewport: viewport });
                controls.querySelector('.pdf-page-info').innerText = `${num} / ${totalPages}`;
                controls.querySelector('.pdf-prev').disabled = (num === 1);
                controls.querySelector('.pdf-next').disabled = (num === totalPages);
            });
        };
        
        pdfjsLib.getDocument(pdfUrl).promise.then(doc => {
            pdfDoc = doc;
            totalPages = doc.numPages;
            renderPage(1);
        }).catch(err => {
            container.innerHTML = `<div style="color:red;">PDF加载失败: ${err.message}</div>`;
        });
        
        controls.querySelector('.pdf-prev').onclick = () => {
            if (currentPage > 1) renderPage(--currentPage);
        };
        controls.querySelector('.pdf-next').onclick = () => {
            if (currentPage < totalPages) renderPage(++currentPage);
        };
        controls.querySelector('.pdf-download').onclick = () => {
            window.open(pdfUrl, '_blank');
        };
    });
</script>

2.3 注意事项

  • 跨域问题:如果 PDF 链接是跨域的,PDF.js 可能无法加载。建议将 PDF 上传到本站,使用同源 URL。

  • 性能:大 PDF 文件可能加载较慢,可增加 loading 提示。

  • 移动端适配:画布宽度自适应,按钮大小适合触摸。

三、优化:在编辑器内预览 PDF(可选)

您也可以在编辑器内部实现 PDF 预览(使用相同的 PDF.js 逻辑),但考虑到编辑器复杂度,建议仅在前台展示即可。用户插入时看到的占位符足够清晰。

四、总结

  • 编辑器:增加了“插入PDF”按钮,支持上传或链接。

  • 前台:使用 PDF.js 渲染,提供翻页控件,左右翻页浏览。

  • 兼容性:现代浏览器均支持,IE 忽略。

发表评论 (0)

留下你的足迹

验证码 点击图片刷新