H5内嵌到APP-实现PDF浏览功能

1、下载插件

javascript 复制代码
npm install vue-pdf-embed vue3-pdfjs

vue3-pdfjs:获取PDF文件总页数

2、页面引入并使用

javascript 复制代码
<template>
  <div class="vuePdfEmbed">
    <div class="wraper" v-if="flagCover">
      <div class="articleTitle">
        {{ reportDetail.title }}
      </div>
      <div class="articleTagBox">
        <div>{{ reportDetail.createTime }}</div>
      </div>
      <div class="articleDetailCover">
        <el-image :src="reportDetail.cover" alt="" lazy class="articleDetailCoverImg" />
      </div>
      <div class="articleIntroduce">
        {{ reportDetail.summary }}
      </div>
    </div>
    <VuePdfEmbed
      :source="state.source"
      :style="scaleFun"
      class="vue-pdf-embed"
      :page="state.pageNum"
      lazy
    />
    <div class="page-tool" v-if="!bottomVisible">
      <div class="page-tool-item" @click="lastPage">上一页</div>
      <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
      <div class="page-tool-item" @click="nextPage">下一页</div>
    </div>
    <!-- 购买提示 -->
    <div class="bottomVisible" v-if="bottomVisible">
      <div class="lock-box">
        <img src="./img/lock.png" alt="" class="lock-box-img" />
        <div>购买后可继续阅读本文档</div>
      </div>
      <div class="buy-box">
        <div class="fixedBoxL">
          <div class="fixedBoxLT">购买全文</div>
          <div class="fixedBoxLB">单篇需付费¥{{ apperMoney }}</div>
        </div>
        <div class="fixedBoxR" @click="goBuyReport">
          立即购买<el-icon><ArrowRightBold /></el-icon>
        </div>
      </div>
    </div>
    <!-- 弹框提示 -->
    <el-dialog v-model="dialogVisible">
      <div class="dialog-box">
        <div class="dialog-text-box">
          <div class="dialog-title">购买后可继续阅读本文档</div>
          <div class="dialog-info">单篇付费只需{{ apperMoney }}元</div>
        </div>
        <div class="dialog-text-box">
          <div class="dialog-btn" @click="goBuyReport">立即购买</div>
          <div class="dialog-close" @click="handleClose">我再想想</div>
        </div>
      </div>
      <div class="dialog-close-box" @click="handleClose"></div>
    </el-dialog>
  </div>
</template>
<script setup>
import {
  LaunchApp,
  detector,
  ua,
  copy,
  supportLink,
  isAndroid,
  isIos,
  inWeixin,
  inQQ,
  inWeibo,
  inBaidu,
} from "web-launch-app";
import { getReportDetailApi } from "@/http/api";
import { ElMessage } from "element-plus";
import { useRoute, useRouter } from "vue-router";
import { reactive, onMounted, ref, onUnmounted } from "vue";
import VuePdfEmbed from "vue-pdf-embed";
import { createLoadingTask } from "vue3-pdfjs"; // 获得总页数
import { ArrowRightBold } from "@element-plus/icons-vue";
const route = useRoute();
const pdfurl = ref("");
const state = reactive({
  source: pdfurl, //预览pdf文件地址
  pageNum: 1, //当前页面
  scale: 1, // 缩放比例
  numPages: 0, // 总页数
});
const scaleFun = reactive({
  transform: "scale(" + state.scale + ")",
});
// 获取上一页
function lastPage() {
  if (state.pageNum > 1) {
    state.pageNum--;
  }
}
// 获取下一页
function nextPage() {
  if (state.pageNum < state.numPages) {
    state.pageNum++;
  }
}
onMounted(() => {
  getReportDetail();
});
// 获取pdf文件
// let flag = ref(false); // 下载按钮的显隐
let flagCover = ref(false); // 封面显隐
let apperMoney = ref(); // 价格
let bottomVisible = ref(false);
const reportDetail = ref({});
function getReportDetail() {
  getReportDetailApi(route.query.id).then((res) => {
    if (res.code == 200) {
      document.title = res.data.title;
      if (res.data.isFree == 1 && res.data.isPurchase == 2) {
        // 付费 且 已解锁
        pdfurl.value = res.data.fileUrl;
        // flag.value = true;
        // 加载异步任务
        const loadingTask = createLoadingTask(state.source);
        // 载入pdf后获取页数
        loadingTask.promise.then((pdf) => {
          state.numPages = pdf.numPages;
        });
      } else if (res.data.isFree == 0) {
        // 免费
        pdfurl.value = res.data.fileUrl;
        // flag.value = true;
        // 加载异步任务
        const loadingTask = createLoadingTask(state.source);
        // 载入pdf后获取页数
        loadingTask.promise.then((pdf) => {
          state.numPages = pdf.numPages;
        });
      } else if (res.data.isFree == 1 && res.data.isPurchase == 1) {
        // 付费 且 未解锁
        // 展示封面图 且 立即购买
        reportDetail.value = res.data;
        // flag.value = false;
        if (route.query.type == "ios") {
          apperMoney.value = res.data.appearIosAmount;
        } else {
          // 安卓现价
          apperMoney.value = res.data.appearAmount;
        }
        bottomVisible.value = true;
        flagCover.value = true;
        timer = setInterval(() => {
          dialogVisible.value = true;
        }, 2000);
      }
    } else {
      ElMessage({
        message: res.msg,
        type: "error",
        plain: true,
      });
    }
  });
}

// 弹框
const dialogVisible = ref(false);
let timer;
function handleClose() {
  dialogVisible.value = false;
  clearInterval(timer);
}
onUnmounted(() => {
  clearInterval(timer);
});

// 立即购买
function goBuyReport() {
  if (isAndroid) {
    androidCscFinanceNews.clickBuyReport(Number(route.query.id));
  } else if (isIos) {
    window.webkit.messageHandlers.clickBuyReport.postMessage([Number(route.query.id)]);
  }
}
</script>
<style>
.vuePdfEmbed {
  flex: 1;
  display: flex;
  height: 100%;
  flex-direction: column;
}
.vuePdfEmbed {
  flex: 1;
  display: flex;
  height: 100%;
  flex-direction: column;
}
.vuePdfEmbed {
  .page-tool {
    position: fixed;
    bottom: 10px;
    left: 50%;
    transform: translateX(-50%);
    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;
    width: 320px;
    align-items: center;
    margin: auto;
    justify-content: space-around;
  }
  .page-tool-item {
    padding: 8px 15px;
    padding-left: 10px;
    cursor: pointer;
  }
}

.el-dialog {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  width: 270px;
  height: 270px;
  background-image: url("./img/dialog.png");
  background-size: contain;
  background-color: transparent;
  box-shadow: none;
}

.el-dialog__headerbtn {
  display: none;
}

.dialog-box {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 100%;
  height: 60%;
  display: flex;
  justify-content: space-around;
  flex-direction: column;
  align-items: center;
}

.dialog-text-box {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.dialog-title {
  font-weight: 500;
  font-size: 20px;
  color: #8b2507;
  line-height: 28px;
}

.dialog-info {
  font-weight: 400;
  font-size: 16px;
  color: #ad705e;
  line-height: 23px;
}

.dialog-btn {
  width: 154px;
  height: 47px;
  background: linear-gradient(360deg, #ff330a 0%, #fc4707 100%);
  box-shadow: 0px 2px 0px 0px #ffa073, inset 1px 5px 9px 0px rgba(255, 255, 255, 0.67);
  font-weight: 500;
  font-size: 17px;
  color: #ffffff;
  line-height: 47px;
  text-align: center;
  border-radius: 80px;
}

.dialog-close {
  font-weight: 400;
  font-size: 12px;
  color: rgba(0, 0, 0, 0.4);
  line-height: 40px;
}

.dialog-close-box {
  position: absolute;
  left: 50%;
  bottom: -60px;
  transform: translateX(-50%);
  width: 36px;
  height: 36px;
  background-image: url("./img/close.png");
  background-size: cover;
}

.lock-box {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 178px;
  background: linear-gradient(180deg, rgba(253, 250, 243, 0.97) 0%, #fef2e6 100%);
  border-radius: 4px 4px 4px 4px;
  text-align: center;
  line-height: 178px;
  font-weight: 400;
  font-size: 14px;
  color: #784122;
}

.lock-box-img {
  display: block;
  width: 13px;
  height: 16px;
  margin-right: 9px;
}

.buy-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 60px;
  background-image: url("./img/bottom.png");
  background-size: cover;
  margin-top: -12px;
  padding: 0 30px;
}

.fixedBoxL {
  padding-top: 10px;
}
.fixedBoxLT {
  font-size: 14px;
  line-height: 20px;
  color: rgba(255, 255, 255, 0.9);
  font-weight: 400;
}

.fixedBoxLB {
  font-size: 10px;
  line-height: 12px;
  color: rgba(255, 255, 255, 0.6);
  font-weight: 400;
}

.fixedBoxR {
  display: flex;
  align-items: center;
  font-size: 16px;
  line-height: 20px;
  color: rgba(255, 255, 255, 0.9);
  font-weight: 500;
}

.bottomVisible {
  position: fixed;
  width: 100%;
  bottom: 0;
  z-index: 2;
}
.articleTitle {
  font-size: 24px;
  color: rgba(0, 0, 0, 0.9);
  line-height: 32px;
  font-weight: 500;
}

.articleTagBox {
  display: flex;
  margin-top: 12px;
  margin-bottom: 20px;
  font-size: 12px;
  line-height: 20px;
  color: rgba(106, 106, 106, 1);
}

.articleDetailCover {
  margin-bottom: 12px;
}

.el-image__inner {
  border-radius: 4px;
}

.articleDetailCoverImg {
  display: block;
  width: 100%;
  border-radius: 4px;
}

.articleIntroduce {
  font-weight: 400;
  font-size: 12px;
  color: #6b6b6b;
  line-height: 22px;
  background: #f6f6f6;
  border-radius: 4px 4px 4px 4px;
  padding: 12px;
  margin-bottom: 12px;
}

.vue-pdf-embed__page canvas {
  width: 100% !important;
}

@media screen and (min-width: 500px) {
  .bottomVisible {
    position: relative;
  }
}
</style>

重点代码:

相关推荐
S. Dylan11 小时前
Edge浏览器打开PDF无法显示电子签章
edge·pdf
一马平川的大草原11 小时前
如何基于pdf2image实现pdf批量转换为图片
计算机视觉·pdf·文件拆分
m0_5945263011 小时前
Python批量合并多个PDF
java·python·pdf
hairenjing112311 小时前
将图片添加到 PDF 的 5 种方法
pdf
✿゚卡笨卡11 小时前
pdf 添加页眉页脚,获取前五页
java·pdf
blegn11 小时前
PDF编辑工具Adobe Acrobat DC 2023安装教程(附安装包)
pdf·办公软件·office
patrickpdx13 小时前
如何调整pdf的页面尺寸
pdf
星月前端16 小时前
【vue-pdf】简单封装pdf预览组件
javascript·vue.js·pdf
Eiceblue20 小时前
Python 在PDF中绘制形状(线条、矩形、椭圆形等)
vscode·python·pycharm·pdf
有过~20 小时前
免费且强大的PDF转换工具——PDFgear
pdf