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>

重点代码:

相关推荐
穆友航11 小时前
PDF内容提取,MinerU使用
数据分析·pdf
拾荒的小海螺1 天前
JAVA:探索 PDF 文字提取的技术指南
java·开发语言·pdf
村东头老张1 天前
Java 实现PDF添加水印
java·开发语言·pdf
好美啊啊啊啊!2 天前
Thymeleaf模板引擎生成的html字符串转换成pdf
pdf·html
zhentiya2 天前
曼昆《经济学原理》第八版课后答案及英文版PDF
大数据·pdf
三天不学习2 天前
如何解决pdf.js跨域从url动态加载pdf文档
javascript·pdf
吾店云建站2 天前
9个最佳WordPress PDF插件(查看器、嵌入和下载)
程序人生·pdf·创业创新·流量运营·程序员创富·教育电商
007php0072 天前
基于企业微信客户端设计一个文件下载与预览系统
开发语言·python·docker·golang·pdf·php·企业微信
慧都小妮子2 天前
Spire.PDF for .NET【页面设置】演示:更改 PDF 页面大小
前端·pdf·.net