vue-pdf-embed+vue3-pdfjs预览pdf文件花屏问题

是根据大佬的教程使用vue-pdf-embed+vue3-pdfjs做的预览pdf文件,但是现在已经找不到大佬的教程了,所以就不贴了。

本文主要记录一下使用这个方法预览pdf文件出现花屏的问题。

问题:

        部分文件出现预览出现花屏失真的问题:

解决过程:

        搜索问题得到答案:

解决使用 pdf.js 时出现花屏问题_vue pdfjs预览pdf花屏-CSDN博客

获得提示:版本问题

先来看一下几个包的版本:

查询npmjs得知vue-pdf-embed有更新

火速更新版本至最新

再次预览文件直接没了,显示不出来了,打印一下报错-----是vue-pdf-embed调用的api和pdfjs-dist的api版本不匹配。

经过排查是vue3-pdfjs中有一个pdfjs-dist包的版本很低,vue-pdf-embed引入了那个包,导致的版本不匹配无法预览,直接卸载vue3-pdfjs解决。

再来看一下版本:

这个时候预览就成功了,也不花屏了

但是vue3-pdfjs的包是用来获取总页数的,卸载后就无法获取总页数了。

使用vue-pdf-embed的loaded,看一下输出:

这个numPages就是总页数

function loaded(data) {
    state.numPages = data._pdfInfo.numPages;
    console.log(data);
}

这样就完美解决了问题。


最后放一下全部代码:

<!--
 * @Author: 赵
 * @Description: pdf预览
 * @Date: 2024-08-14 13:43:49
 * @LastEditTime: 2024-11-06 11:13:15
 * @FilePath: 
-->
<template>
    <div class="pdf-preview">
        <div class="pdf-wrap">
            <vue-pdf-embed 
                :source="state.source" 
                :style="scale" 
                class="vue-pdf-embed" 
                :page="state.pageNum" 
                ref="PdfEmbedRef"
                @loading-failed="loadingFild"
                @loaded="loaded"
            />
        </div>

        <div class="bottom" v-if="props.controlBottom">
            <div class="page-tool">
                <div class="page-tool-item" @click="lastPage">上一页</div>
                <div class="page-tool-item" @click="nextPage">下一页</div>
                <div class="page-tool-item" style="display: flex;justify-content: center; align-items: center">
                    <!-- {{ state.pageNum }}/{{ state.numPages }} -->
                    <a-input-number 
                        v-model:value="state.pageNum" 
                        :min="1" 
                        :max="state.numPages" 
                        :controls="false" 
                        size="small"
                        style="width: 40px;margin-right: 5px;"
                    />
                    <div>
                        /{{state.numPages}}
                    </div>
                </div>
                <div class="page-tool-item" @click="pageZoomOut">放大</div>
                <div class="page-tool-item" @click="pageZoomIn">缩小</div>
                <div class="page-tool-item" @click="pageRest">重置缩放</div>
                <div class="page-tool-item" @click="downloadPdf">下载</div>
                <div class="page-tool-item" @click="onClose">关闭</div>
            </div>
        </div>

        <div class="separate" v-if="!props.controlBottom">
            <div class="page-tool page-tool-zoom">
                <div class="page-tool-item" @click="pageZoomOut" style="font-size: 25px;">
                    <!-- 放大 -->
                    <ZoomInOutlined />
                </div>
                <div class="page-tool-item" @click="pageZoomIn" style="font-size: 25px;">
                    <!-- 缩小 -->
                    <ZoomOutOutlined />
                </div>
            </div>
            <div class="page-tool page-tool-page">
                <div class="page-tool-item" @click="lastPage" style="font-size: 25px;">
                    <!-- 上一页 -->
                    <LeftOutlined />
                </div>
                <div class="page-tool-item-page">
                    <a-input-number 
                        v-model:value="state.pageNum" 
                        :min="1" 
                        :max="state.numPages" 
                        :controls="false" 
                        size="small"
                        style="width: 50px;margin-right: 5px;"
                    />
                    <div>
                        /{{state.numPages}}
                    </div>
                </div>
                <div class="page-tool-item" @click="nextPage" style="font-size: 25px;">
                    <!-- 下一页 -->
                    <RightOutlined />
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { onMounted, ref, reactive, computed, defineEmits, watch } from "vue";
import VuePdfEmbed from "vue-pdf-embed";

import _ from "lodash";

const props = defineProps({
    pdfUrl: {
        type: String,
    },
    controlBottom: {
        type: Boolean,
        default: true,
    }
})
const state = reactive({
  source: {
    url: props.pdfUrl,
    // cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.9.359/cmaps/',
    // cMapPacked: true
  }, //预览pdf文件地址
  pageNum: 1, //当前页面
  scale: 1, // 缩放比例
  numPages: 0, // 总页数
})

watch(
    () => state.pageNum,
    (value) => {
        if(!value) {                        // 还没输入
            state.pageNum = 1;
        }
        if(value > state.numPages) {        //超出总页数
            state.pageNum = state.numPages;
        }
    }
)

const scale = computed(() => `transform:scale(${state.scale})`)
function lastPage() {           // 上一页
    if (state.pageNum > 1) {
        state.pageNum -= 1;
    }
}
function nextPage() {         // 下一页
    if (state.pageNum < state.numPages) {
        state.pageNum += 1;
    }
}
function pageZoomOut() {        // 放大
    if (state.scale < 5) {
        state.scale += 0.1;
    }
}
function pageZoomIn() {        // 缩小
    if (state.scale > 0.3) {
        state.scale -= 0.1;
    }
}

// 页面 缩放 还原默认值
function pageRest() {
    state.scale = 1.0;
}

// 下载功能
const PdfEmbedRef = ref();
function downloadPdf() {
    PdfEmbedRef.value.download();
}

const emits = defineEmits("close")
// 关闭modal
function onClose() {
    emits("close");
}

// --------------- 鼠标拖动-----------------------
let draggable;
let active = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;

function dragStart(e) {
    initialX = e.clientX - xOffset;
    initialY = e.clientY - yOffset;

    console.dir(draggable);
    if (draggable.className === "pdf-wrap") {
        active = true;
    }
}

function dragEnd(e) {
    initialX = currentX;
    initialY = currentY;

    active = false;
}

function drag(e) {
    if (active) {
        e.preventDefault();
        currentX = e.clientX - initialX;
        currentY = e.clientY - initialY;

        xOffset = currentX;
        yOffset = currentY;

        setTranslate(currentX, currentY, draggable);
    }
}

function setTranslate(xPos, yPos, el) {
    el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
}

function loadingFild(data) {
    console.log(data);
}

function loaded(data) {
    state.numPages = data._pdfInfo.numPages;
    console.log(data);
}

onMounted(() => {
    // -------- 鼠标拖动 -------------
    // new Draggable(document.querySelector(".pdf-wrap"));
    draggable = document.querySelector(".pdf-wrap");
    draggable.addEventListener('mousedown', dragStart, false);
    document.addEventListener('mouseup', dragEnd, false);
    document.addEventListener('mousemove', drag, false);

    const pdfPreview = document.querySelector(".pdf-preview");
    pdfPreview.addEventListener('mouseenter',() => {
        window.addEventListener('wheel', wheel);
    },false);

    pdfPreview.addEventListener('mouseleave',() => {
        window.removeEventListener('wheel',wheel);
    })
})

function wheel(e) {     // 放大缩小事件
    // e.preventDefault();
    if(e.deltaY < 0) {      // 放大
        pageZoomOut();
    } else {            // 缩小
        pageZoomIn();
    }
}




</script>

<style lang="less" scoped>
.pdf-preview {
    position: relative;
    height: 100%;
    background-color: #ccc;
    box-sizing: border-box;
    overflow: hidden;
}
.vue-pdf-embed {
    text-align: center;
    width: 515px;
    height: 100%;
    border: 1px solid #e5e5e5;
    margin: 0 auto;
    box-sizing: border-box;
}



.bottom {
    .page-tool {
        position: absolute;
        bottom: 8%;
        padding-left: 15px;
        padding-right: 15px;
        display: flex;
        align-items: center;
        background: rgb(66, 66, 66);
        color: white;
        border-radius: 19px;
        z-index: 100;
        cursor: pointer;
        margin-left: 50%;
        transform: translateX(-50%);
        user-select: none;
        white-space: nowrap;
        .page-tool-item {
            padding: 8px 15px;
            padding-left: 10px;
            cursor: pointer;
        }
    }
}










.separate {
    .page-tool {
        position: fixed;
        display: flex;
        padding: 10px 0;
        align-items: center;
        background: rgb(66, 66, 66);
        color: white;
        border-radius: 19px;
        cursor: pointer;
        user-select: none;
    
    }
    
    .page-tool-zoom {
        right: 20px;
        top: 50%;
        transform: translate(-50%,-50%);
        flex-direction: column;
        justify-content: center;
        .page-tool-item {
            padding: 8px 15px;
            cursor: pointer;
        }
    }
    
    .page-tool-page {
        position: absolute;
        left: 50%;
        bottom: 2%;
        transform: translateX(-50%);
        .page-tool-item {
            padding: 8px 15px;
            cursor: pointer;
        }
        .page-tool-item-page {
            display: flex;
            align-items: center;
            justify-content: center;
        }
    }
}

</style>

效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值