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>

重点代码:

相关推荐
琉璃℡初雪2 分钟前
vue2/3 中使用 @vue-office/docx 在网页中预览(docx、excel、pdf)文件
vue.js·pdf·excel
一个懒鬼4 小时前
Edge浏览器打开PDF文件显示空白(每次需要等上一会)
windows·pdf
Lauren_Lu13 小时前
pdf 不是扫描件,但却无法搜索关键词【问题尝试解决未果记录】
pdf
Python猫1 天前
付费专栏·Python潮流周刊电子书合集(epub、pdf、markdown)下载
python·计算机·pdf·电子书·资料
JackieZhengChina1 天前
用python清除PDF文件中的水印(Adobe Acrobat 无法删除)
pdf
geovindu1 天前
vue3: pdf.js 3.4.120 using javascript
开发语言·javascript·vue.js·pdf
TextIn智能文档云平台2 天前
PDF文档解析新突破:图表识别、公式还原、手写字体处理,让AI真正读懂复杂文档!
图像处理·人工智能·算法·自然语言处理·pdf·ocr
old_power2 天前
【Python】PDF文件处理(PyPDF2、borb、fitz)
python·pdf
belldeep2 天前
vite:npm 安装 pdfjs-dist , PDF.js View 预览功能示例
javascript·pdf·pdfjs-dist·pdf.worker
dtzly2 天前
若依定制pdf生成实战
pdf