pdf 预览 @sunsetglow/vue-pdf-viewer 无需二次开发,开箱即用

2,035 阅读5分钟

@sunsetglow/vue-pdf-viewer

开箱即用的pdf插件@sunsetglow/vue-pdf-viewer, vue3 版本 无需多余开发,操作简单,支持大文件 pdf 滚动加载,文件搜索,水印,缩放,左侧导航,下载,页码,打印,文本复制,等功能

image.png

移动端展示

7D83447E-9463-46d2-B2C1-EA32922F2A3C.png

举个栗子

  • 首先就是我们先去安装我们的npm 包
yarn add @sunsetglow/vue-pdf-viewer
npm i @sunsetglow/vue-pdf-viewer
pnpm i @sunsetglow/vue-pdf-viewer
  • 话不多说直接上代码 (此代码是0.3.55之前的方法)
 
 <template>
  <div id="pdf-container"></div>
</template>
<script lang="ts" setup>
import {
  initPdfView,
  configPdfApiOptions,
  configOption,
} from "@sunsetglow/vue-pdf-viewer";
import "@sunsetglow/vue-pdf-viewer/dist/style.css";
import { onMounted } from "vue";
const loading = ref(false);
const pdfPath = new URL(
  "@sunsetglow/vue-pdf-viewer/dist/libs/pdf.worker.min.js",
  import.meta.url
).href;
onMounted(() => {
  loading.value = true;
  initPdfView(document.querySelector("#pdf-container") as HTMLElement, {
    loadFileUrl: `https:xxx.pdf`, //文件路径
    pdfPath: pdfPath, // pdf.js 里需要指定的文件路径
    loading: (load: boolean, fileInfo: { totalPage: number }) => {
      loading.value = load;
      console.log(`pdf 文件总数:${fileInfo.totalPage}`);
      //加载完成会返回 false
      configPdfApiOptions.onSearch("产品力成为推动其发展", false);
    },
    pdfOption: {
      search: true, // 搜索 开启搜索必须开启textLayer 为true
      scale: true, //缩放
      pdfImageView: false, //pdf 是否可以单片点击预览
      page: true, //分页查看
      navShow: true, //左侧导航
      navigationShow: false, // 左侧导航是否开启
      pdfViewResize: true, // 是否开启resize 函数 确保pdf 根据可视窗口缩放大小
      toolShow: true, // 是否开启顶部导航
      download: true, //下载
      clearScale: 1.5, // 清晰度 默认1.5 感觉不清晰调大 ,当然清晰度越高pdf生成性能有影响
      fileName: "preview.pdf", // pdf 下载文件名称
      lang: "en", //字典语言
      print: true, //打印功能
      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。可解决字体加载错误
      },
      textLayer: true, //文本是否可复制 , 文本复制和点击查看大图冲突建议把 pdfImageView 改为false
      pageOption: {
        current: 1, //当前页码
      },
      renderTotalPage: -1, //是否渲染指定页面总数,-1 则默认渲染文件总数,如果传5 则渲染前五页
      // 不传默认是 0.5
      visibleWindowPageRatio: 0.5, //当前pdf页面在可视窗口多少比例触发分页 传入0.5 就是 (pdf下一页滚动到容器高度一半的时候 更新当前页码)
      containerWidthScale: 0.97, //pdf 文件占父元素容器width的比例 默认是0.8
      pdfItemBackgroundColor: "#fff", //pdf 加载时背景颜色 默认#ebebeb
      watermarkOptions: {
        //水印功能
        columns: 3, //列数量
        rows: 4, // 行数量
        color: "#2f7a54", //字体颜色
        rotation: 25, //旋转角度
        fontSize: 40, //字体大小
        opacity: 0.4, //调整透明度
        watermarkTextList: ["第一行", "第二行", "第三行"], //水印文字和 watermarkLink 冲突,只能展示一个水印内容
        // watermarkLink: "https://xxx.png", //水印可以支持公司logo(图片路径)
      }, // 不展示水印传 undefined即可
    },
  });
});
// 监听内容页码变化
watch(
  () => configOption.value?.pageOption?.current,
  (current) => {
    console.log(current, "当前页码");
  }
);
</script>

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

  • 如果是0.3.55 以及之后的代码 请复制以下代码
<template>
  <div id="pdf-container"></div>
</template>
<script lang="ts" setup>
import {
  initPdfView,
  usePdfConfigState
} from "@sunsetglow/vue-pdf-viewer";
import "@sunsetglow/vue-pdf-viewer/dist/style.css";
import { onMounted } from "vue";
const loading = ref(false);
const url = ref("https:xxx.pdf");
const pdfPath = new URL(
  "@sunsetglow/vue-pdf-viewer/dist/libs/pdf.worker.min.js",
  import.meta.url
).href;
let configOption = ref<pdfOption>() as any;
let configPdfApiOptions = ref() as any;
onMounted(() => {
  loading.value = true;
   const { app } = initPdfView(document.querySelector("#pdf-container") as HTMLElement, {
    loadFileUrl: url, //文件路径 string | ArrayBuffer | Uint8Array|Ref<string> 响应式内部会监听
    pdfPath: pdfPath, // pdf.js 里需要指定的文件路径
    loading: (load: boolean, fileInfo: { totalPage: number }) => {
      loading.value = load;
      console.log(`pdf 文件总数:${fileInfo.totalPage}`);
      //加载完成会返回 false
      nextTick(() => {
        configPdfApiOptions?.value?.handleChange(4);
      });
    },
      onError: (erorr: Error ) => {
        console.log(erorr, "报错内容处理");
      },
    pdfOption: {
      search: true, // 搜索 开启搜索必须开启textLayer 为true
      searchToolVisible: false, // 是否展示搜索图标和搜索下拉框 ,,默认true
      scale: true, //缩放
      pdfImageView: false, //pdf 是否可以单片点击预览
      page: true, //分页查看
      navShow: true, //左侧导航
      navigationShow: false, // 左侧导航是否开启
      pdfViewResize: true, // 是否开启resize 函数 确保pdf 根据可视窗口缩放大小
      toolShow: true, // 是否开启顶部导航
      download: true, //下载
      clearScale: 1.5, // 清晰度 默认1.5 感觉不清晰调大 ,当然清晰度越高pdf生成性能有影响
      fileName: "preview.pdf", // pdf 下载文件名称
      lang: "en", //字典语言
      print: true, //打印功能
      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。可解决字体加载错误
      },
      textLayer: true, //文本是否可复制 , 文本复制和点击查看大图冲突建议把 pdfImageView 改为false
      pageOption: {
        current: 1, //当前页码
      },
      renderTotalPage: 5, //是否渲染指定页面总数,-1 则默认渲染文件总数,如果传5 则渲染前五页
      // 不传默认是 0.5
      visibleWindowPageRatio: 0.5, // 下一个页面展示的比例触发页码变更 默认0.5(可选)
      containerWidthScale: 0.97, //pdf 文件占父元素容器width的比例 默认是0.8
      containerScale: 0.8, //缩放功能的初始值 会和 containerWidthScale 参数重和(展示用默认1组件内部会 containerScale * 100 )
      pdfItemBackgroundColor: "#fff", //pdf 加载时背景颜色 默认#ebebeb (可选)
       pdfBodyBackgroundColor: '#eaeaea'; //pdf 容器的背景色 默认#eaeaea (可选)
       pdfListContainerPadding: "10px 20px 20px 20px", // pdf 容器的padding默认10px 20px 20px(可选)
      watermarkOptions: {
        //水印功能
        columns: 3, //列数量
        rows: 4, // 行数量
        color: "#2f7a54", //字体颜色
        rotation: 25, //旋转角度
        fontSize: 40, //字体大小
        opacity: 0.4, //调整透明度
        watermarkTextList: ["第一行", "第二行", "第三行"], //水印文字和 watermarkLink 冲突,只能展示一个水印内容
        // watermarkLink: "https://xxx.png", //水印可以支持公司logo(图片路径)
      }, // 不展示水印传 undefined即可
      selectConfig: [
        //自定义选中文字弹窗不需要该功能不穿此参数即可
        {
          icon: SearchOutlined, //图标 Component
          text: ` AI 搜索`, // 文字
          style: { color: "red" }, // style
          onClick: (text: string) => {
            // 自定义实现功能
            console.log("选中文字", text);
          },
        },
        {
          icon: FileSearchOutlined,
          text: `联网搜索`,
          onClick: (text: string) => {
            // 需自定义实现功能
            console.log("选中文字", text);
          },
        },
        {
          icon: CopyOutlined,
          text: `复制`,
          onClick: (text: string, onCopy) => {
            // 组件内置实现的copy函数该功能直接调用即可
            onCopy(text);
            console.log("选中文字", text);
          },
        },
      ],
      // 不需要的话不传此参数就行 ,(pdf展示大小变化会触发函数)
       getPdfScaleView: (params: {
        scale?: number; //pdf 原始宽高和 展示pdf 宽高换算的 缩放值
        pdfViewport?: { width: number; height: number }; //文件宽高
      }) => {
        console.log(params, "scale");
      },
      /**
       * 可选(不需要不传入即可)
       * @param container 打印pdf容器(会生成一份完整pdf)
       * @param onClose //关闭内部状态函数
       */
      handleCustomPrint: (container: HTMLElement, onClose: Function) => {
        const printContent = container?.innerHTML;
        const iframe = document.createElement("iframe");
        iframe.setAttribute(
          "style",
          "position: absolute; width: 0; height: 0;display: none;"
        );
        document.body.appendChild(iframe);
        if (iframe?.contentWindow?.document) {
          const iframeDoc = iframe.contentWindow.document;
          iframeDoc.write(`<style media="print">@page {size: auto;  margin: 0;}  body {
              margin: 1cm;
                  }
                img{
                  max-width:100%;
                  width:88%;
                  margin:0px auto;
                  height:auto;
                }  </style>`);
          iframeDoc.write(
            `<link href="./print.css" media="print" rel="stylesheet" />`
          );
          iframe.contentWindow.onafterprint = function () {
            document.body.removeChild(iframe);
            // container?.innerHTML && (container.innerHTML = "");
          };
          iframeDoc.write("<div>" + printContent + "</div>");
          // 调用内部关闭弹窗函数
          onClose();
          iframe.contentWindow?.print();
        } else {
          document.body.removeChild(iframe);
        }
      },
    },
  });
  // 从内部实例拿到数据进行监听
  const config  = usePdfConfigState(app)
  // 监听内部状态
   configOption.value = config.configOption.value;
  //  configPdfApiOptions 函数在loading 执行之后调用
  configPdfApiOptions.value = config.configPdfApiOptions;
});
// 监听内容页码变化
watch(
  () => configOption.value?.pageOption?.current,
  (current) => {
    console.log(current, "当前页码");
  },
  {
    deep: true,
  }
);

/**
 * 获得搜索内容总数和选中当前选中页数
 */
 watch(
  () => configOption.value?.searchOption?.searchTotal,
  () => {
    if (configOption.value?.searchOption) {
      const { searchIndex, searchTotal } = configOption.value?.searchOption;
      console.log(`当前选中页码:${searchIndex}, 搜索匹配总数:${searchTotal}`);
    }
  },
  {
    deep: true,
  }
);
// 监听内部缩放值
watch(
  () => configOption.value?.containerScale,
  (containerScale) => {
    console.log(`内部缩放值:${containerScale},  `);
  },
  { deep: true, }
);
</script>

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

参数说明

参数名称内容 说明类型
loadFileUrlpdf 文件路径 (必选)ref 内部会监听其他类型不会string,ArrayBuffer,Uint8Array,Ref
pdfPathpdf.js 里所需的 pdf.worker.min.js 指向地址(必选)string
pdfOptionpdf 的配置选项 (可选)pdfOption
loadingpdf 加载完成执行函数 (可选)Function
onError组件内部报错函数处理 (可选)Function

api 事件说明

  • 对外开放 api 通一在 configPdfApiOptions 对象上
import { configPdfApiOptions } from "@sunsetglow/vue-pdf-viewer";
/**
 * 控制pdf 跳到指定页码
 * @param index
 * 类型 number
 */
configPdfApiOptions.handleChange(1);
/**
 * 搜索内置函数(在loading 函数里调用)
 * @param keyword 搜索内容
 * @param visible 是否展示搜索框 true
 * @param isNext 是否自动跳转匹配到搜索结果页 默认跳转 true
 */
configPdfApiOptions.onSearch("产品力成为推动其发展", false);

/**
 * 需要在onSearch函数执行之后调用
 * 搜索到匹配条件执行下一步 上一步函数
 * @param type next(下一步) |  previous(上一步)
 * @returns
 */
configPdfApiOptions.onSearchNext("next");

🎆 欢迎大家的使用

  • 如果帮助到你,帮忙点个 star ,有任何改进可直接提 issue 或者私信邮箱 wyaoting999@163.com

  • github 仓库地址 sunsetglow-vue-pdf-viewer

  • 最简单ctrl+c ctrl+v

  • 但是我们需要注意的是pdfPath这个参数需要一个指向 pdf.worker.min.js 文件的路径

  • 做完以上步骤我们大功告成了