PdfPreview.vue 5.38 KB
<!--
 * @Date: 2024-01-17
 * @Description: PDF预览组件
-->
<template>
    <van-popup v-if="show" :show="show" @update:show="emit('update:show', $event)" position="right"
        :style="{ height: '100%', width: '100%' }">
        <div id="pdf-container" class="pdf-no-select"></div>
        <van-button class="close-btn" type="default" icon="cross" round @click="emit('update:show', false)" />
        <van-overlay :show="loading">
            <div class="wrapper" @click.stop>
                <van-loading vertical color="#FFFFFF">加载中...</van-loading>
            </div>
        </van-overlay>
    </van-popup>
</template>

<script setup>
import { ref, nextTick, onMounted, computed } from 'vue';
import { initPdfView, configPdfApiOptions } from "@sunsetglow/vue-pdf-viewer";
import "@sunsetglow/vue-pdf-viewer/dist/style.css";

const props = defineProps({
    show: {
        type: Boolean,
        default: false
    },
    url: {
        type: String,
        default: ''
    },
    title: {
        type: String,
        default: ''
    }
});

const emit = defineEmits(['update:show', 'onLoad']);

// PDF Worker路径
const loading = ref(true);
const pdfPath = new URL("@sunsetglow/vue-pdf-viewer/dist/libs/pdf.worker.min.js", import.meta.url).href;

// 监听show属性变化
watch(() => props.show, (newVal) => {
    if (newVal && props.url) {
        loading.value = true;
        initPdfViewer();
    }
});

// 初始化PDF预览
// 查看文档 https://www.npmjs.com/package/@sunsetglow/vue-pdf-viewer
const initPdfViewer = () => {
    nextTick(() => {
        initPdfView(document.querySelector("#pdf-container"), {
            loadFileUrl: props.url,
            pdfPath: pdfPath,
            loading: (load, fileInfo) => {
                loading.value = load;
                emit('onLoad', false);
            },
            pdfOption: {
                search: false,
                scale: true,
                pdfImageView: true,
                page: true,
                navShow: true,
                navigationShow: false,
                pdfViewResize: true,
                toolShow: false,
                download: false, // 禁用下载功能
                clearScale: 1.75,
                fileName: props.title,
                lang: "zh",
                print: false, // 禁用打印功能
                watermarkOptions: undefined,
                customPdfOption: {
                    // customPdfOption是 pdfjs getDocument 函数中一些配置参数 具体可参考 https://mozilla.github.io/pdf.js/api/draft/module-pdfjsLib.html#~DocumentInitParameters
                    cMapPacked: true, //指定 CMap 是否是二进制打包的
                    cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/", //预定义 Adob​​e CMaps 所在的 URL。可解决字体加载错误
                },
                // 禁用右键菜单和文本选择
                selectConfig: undefined, // 禁用文本选择功能
            }
        });
        
        // 添加额外的事件监听器来防止长按保存
        const pdfContainer = document.querySelector("#pdf-container");
        if (pdfContainer) {
            // 防止上下文菜单(右键菜单)
            pdfContainer.addEventListener('contextmenu', (e) => {
                e.preventDefault();
                return false;
            });
            
            // 防止长按选择
            pdfContainer.addEventListener('selectstart', (e) => {
                e.preventDefault();
                return false;
            });
            
            // 防止拖拽
            pdfContainer.addEventListener('dragstart', (e) => {
                e.preventDefault();
                return false;
            });
        }
    });
};
</script>

<style scoped>
#pdf-container {
    width: 100%;
    padding: 0px;
    height: 100%;
}

/* 防止PDF图片被长按保存的样式 */
.pdf-no-select {
    -webkit-user-select: none; /* Safari */
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* IE10+/Edge */
    user-select: none; /* Standard */
    -webkit-touch-callout: none; /* iOS Safari */
    -webkit-tap-highlight-color: transparent; /* 移除点击高亮 */
    pointer-events: auto; /* 保持可点击 */
}

/* 深度选择器,防止PDF内部图片被保存 */
:deep(.pdf-no-select img) {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    pointer-events: none; /* 禁用图片的所有交互 */
    -webkit-user-drag: none; /* 禁止拖拽 */
    -khtml-user-drag: none;
    -moz-user-drag: none;
    -o-user-drag: none;
    user-drag: none;
}

/* 防止右键菜单 */
:deep(.pdf-no-select canvas) {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    pointer-events: none;
    -webkit-user-drag: none;
    -khtml-user-drag: none;
    -moz-user-drag: none;
    -o-user-drag: none;
    user-drag: none;
}

.close-btn {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 100;
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
}

.wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
}
</style>