You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于pdf.js的网页PDF展示:移动端无法旋转、缩放问题排查

解决PDF.js移动端显示过小、无法缩放旋转的问题

问题根源

  1. 固定Canvas尺寸导致适配失效:原代码里canvas硬编码了width="2000",移动端屏幕宽度远小于该值,页面渲染时会压缩canvas显示,导致内容过小;同时未考虑设备像素比(DPR),渲染的PDF会出现模糊。
  2. 缺少缩放、旋转逻辑:原代码没有维护缩放比例和旋转角度的变量,也没有对应的交互控制逻辑。

解决方案

1. 修改HTML与基础样式

调整结构,给PDF容器添加适配样式,移除canvas的固定宽度,同时增加缩放旋转控制按钮:

<div class="slides-player__body bg-grey-light" style="position: relative; overflow: auto; height: 100vh;">
    <div id="pdf-contents">
        <!-- 移除固定width,由JS动态设置 -->
        <canvas id="pdf-canvas" class="start-image"></canvas>
        <div id="page-loader" style="padding-top:20px; text-align:center;">
            <p>Loading page ... <i class="fa fa-spinner fa-spin"></i></p>
        </div>
    </div>
    <!-- 添加缩放旋转、翻页控制按钮 -->
    <div style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; background: #fff; padding: 8px 12px; border-radius: 20px;">
        <button id="pdf-zoom-out" style="border: none; background: transparent; font-size: 18px; padding: 0 8px;">-</button>
        <button id="pdf-zoom-in" style="border: none; background: transparent; font-size: 18px; padding: 0 8px;">+</button>
        <button id="pdf-rotate" style="border: none; background: transparent; font-size: 18px; padding: 0 8px;">↻</button>
        <span style="border-left: 1px solid #eee; height: 20px;"></span>
        <button id="pdf-prev" style="border: none; background: transparent; font-size: 18px; padding: 0 8px;">←</button>
        <button id="pdf-next" style="border: none; background: transparent; font-size: 18px; padding: 0 8px;">→</button>
    </div>
</div>

2. 优化JS逻辑(适配+缩放+旋转)

修改JS代码,添加视口适配、设备像素比处理、缩放旋转功能,同时监听窗口resize事件:

var __PDF_DOC,
    __CURRENT_PAGE,
    __TOTAL_PAGES,
    __PAGE_RENDERING_IN_PROGRESS = 0,
    __CANVAS = $('#pdf-canvas').get(0),
    __CANVAS_CTX = __CANVAS.getContext('2d'),
    __SCALE = 1.0, // 初始缩放比例
    __ROTATE = 0; // 初始旋转角度(0/90/180/270)

var location_pdf = "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf";  
showPDF(location_pdf);

// 监听窗口尺寸变化,重新渲染当前页
window.addEventListener('resize', function() {
    if (__PDF_DOC && !__PAGE_RENDERING_IN_PROGRESS) {
        showPage(__CURRENT_PAGE);
    }
});

// 绑定缩放旋转按钮事件
$('#pdf-zoom-in').click(function() {
    if (__SCALE < 2.5) { // 限制最大缩放比例
        __SCALE += 0.2;
        showPage(__CURRENT_PAGE);
    }
});

$('#pdf-zoom-out').click(function() {
    if (__SCALE > 0.5) { // 限制最小缩放比例
        __SCALE -= 0.2;
        showPage(__CURRENT_PAGE);
    }
});

$('#pdf-rotate').click(function() {
    __ROTATE = (__ROTATE + 90) % 360;
    showPage(__CURRENT_PAGE);
});

// 翻页按钮逻辑
$('#pdf-prev').click(function() {
    if (__CURRENT_PAGE > 1) {
        showPage(__CURRENT_PAGE - 1);
    }
});

$('#pdf-next').click(function() {
    if (__CURRENT_PAGE < __TOTAL_PAGES) {
        showPage(__CURRENT_PAGE + 1);
    }
});

function showPDF(pdf_url) {
    $("#pdf-loader").show();

    PDFJS.getDocument({ url: pdf_url }).then(function(pdf_doc) {
        __PDF_DOC = pdf_doc;
        __TOTAL_PAGES = __PDF_DOC.numPages;
        
        $("#pdf-loader").hide();
        $("#pdf-contents").show();
        $("#pdf-total-pages").text(__TOTAL_PAGES);

        // 默认显示第一页(兼容current_slide不存在的情况)
        var pg = document.getElementById("current_slide")?.value || 1;
        showPage(parseInt(pg));
    }).catch(function(error) {
        $("#pdf-loader").hide();
        $("#upload-button").show();
        alert(error.message);
    });
}

function showPage(page_no) {
    __PAGE_RENDERING_IN_PROGRESS = 1;
    __CURRENT_PAGE = page_no;

    // 禁用所有控制按钮直到渲染完成
    $("#pdf-next, #pdf-prev, #pdf-zoom-in, #pdf-zoom-out, #pdf-rotate").attr('disabled', 'disabled');

    $("#pdf-canvas").hide();
    $("#page-loader").show();

    $("#pdf-current-page").text(page_no);
    
    __PDF_DOC.getPage(page_no).then(function(page) {
        // 获取容器宽度,适配移动端屏幕
        var containerWidth = $('#pdf-contents').width();
        // 计算基础缩放比例:让PDF宽度适配容器,叠加自定义缩放比例
        var viewport = page.getViewport({
            scale: __SCALE,
            rotation: __ROTATE
        });

        // 考虑设备像素比,避免PDF渲染模糊
        var dpr = window.devicePixelRatio || 1;
        __CANVAS.width = viewport.width * dpr;
        __CANVAS.height = viewport.height * dpr;
        __CANVAS.style.width = viewport.width + 'px';
        __CANVAS.style.height = viewport.height + 'px';

        __CANVAS_CTX.scale(dpr, dpr);

        var renderContext = {
            canvasContext: __CANVAS_CTX,
            viewport: viewport
        };
        
        page.render(renderContext).then(function() {
            __PAGE_RENDERING_IN_PROGRESS = 0;
            // 重新启用控制按钮
            $("#pdf-next, #pdf-prev, #pdf-zoom-in, #pdf-zoom-out, #pdf-rotate").removeAttr('disabled');
            $("#pdf-canvas").show();
            $("#page-loader").hide();
        });
    });
}

关键改动说明

  • 移动端适配:不再固定canvas宽度,根据容器宽度动态计算渲染尺寸,同时加入设备像素比处理,解决PDF模糊问题。
  • 缩放功能:通过__SCALE变量控制渲染比例,绑定按钮实现缩放增减,限制缩放范围避免显示异常。
  • 旋转功能:通过__ROTATE变量控制页面旋转角度,每次点击增加90度,循环生效。
  • 窗口resize监听:屏幕尺寸变化时自动重新渲染,保持PDF始终适配当前屏幕。

内容的提问来源于stack exchange,提问作者irwan dwiyanto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:00:54