PdfViewer.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <template>
  2. <div class="vue-pdf" @scroll="onScroll" ref="myDiv">
  3. <vue-pdf-embed :source="testpdf1" ref="vuePdfRef" :style="scaleFun" class="vue-pdf-cs" @loaded="onPdfLoaded" :renderPageNumber="true" />
  4. </div>
  5. <div class="page-tool" v-show="isToolVisible">
  6. <div class="page-tool-item" @click="lastPage">上一页</div>
  7. <div class="page-tool-item" @click="nextPage">下一页</div>
  8. <div class="page-tool-item" @click="pageZoomOut">放大</div>
  9. <div class="page-tool-item" @click="pageZoomIn">缩小</div>
  10. <div class="page-tool-item" @click="PDFPrint">打印</div>
  11. <div class="page-tool-item" @click="PDFDownload">下载</div>
  12. </div>
  13. <div class="page-tool2" v-show="isToolVisible">
  14. <div class="page-tool-item2" @click="lastPage">{{scaleData.pageNum}}/{{scaleData.numPages}}</div>
  15. </div>
  16. </template>
  17. <script setup lang="ts" v-show="isToolVisible">
  18. import VuePdfEmbed from 'vue-pdf-embed';
  19. import testpdf1 from '../../assets/testpdf.pdf';
  20. import {computed, onMounted, reactive, ref} from "vue";
  21. const isToolVisible = ref(false)
  22. // 实现pdf缩放
  23. const scaleFun = computed(() => {
  24. return {
  25. transform: `scale(${scaleData.scale})`,
  26. transition: 'all 0.3s',
  27. transformOrigin: 'top'
  28. };
  29. });
  30. const scaleData = reactive({
  31. scale: 0.6, // 缩放比例
  32. scaleNum: 0.1, // 滚轮缩放比例
  33. scaleMax: 100, // 最大缩放比例
  34. scaleMin: 0.1, // 最小缩放比例
  35. scaleBtn: 0.4, // 缩放按钮缩放比例
  36. pageNum: 1, // 当前页面
  37. url: 'http://www.fao.fudan.edu.cn/_upload/article/files/f5/53/8b40af524563b9b60049899b2dd3/c9a205b4-4188-4af3-863e-bc4e56872e33.pdf',
  38. numPages: 0
  39. });
  40. const vuePdfRef = ref<InstanceType<typeof VuePdfEmbed> | null>(null);
  41. const myDiv = ref();
  42. const lastPage = () => {
  43. if (scaleData.pageNum > 1) {
  44. scaleData.pageNum--
  45. scrollToPage()
  46. }
  47. };
  48. const nextPage = () => {
  49. if (scaleData.pageNum < scaleData.numPages) {
  50. scaleData.pageNum++
  51. scrollToPage()
  52. }
  53. };
  54. const pageZoomOut = () => {
  55. if (scaleData.scale < scaleData.scaleMax) {
  56. scaleData.scale += scaleData.scaleNum;
  57. }
  58. };
  59. const pageZoomIn = () => {
  60. if (scaleData.scale > scaleData.scaleMin) {
  61. scaleData.scale -= scaleData.scaleNum;
  62. }
  63. };
  64. const PDFPrint = () => {
  65. vuePdfRef.value?.print(300, getPDFFileName(), true)
  66. };
  67. const PDFDownload = () => {
  68. vuePdfRef.value?.download(getPDFFileName())
  69. };
  70. const getPDFFileName = () => {
  71. const last_index= scaleData.url.lastIndexOf('/');
  72. return scaleData.url.slice(last_index+ 1);
  73. };
  74. const onPdfLoaded = (data: { numPages: number }) => {
  75. scaleData.numPages = data.numPages
  76. };
  77. const scrollToPage = () => {
  78. const pdfContainer = myDiv.value;
  79. const pageHeight = pdfContainer.scrollHeight / scaleData.numPages;
  80. const targetScrollPosition = (scaleData.pageNum-1) * pageHeight;
  81. pdfContainer.scrollTo({
  82. top: targetScrollPosition,
  83. behavior: 'smooth'
  84. });
  85. };
  86. const onScroll = () => {
  87. const pdfContainer = myDiv.value;
  88. const scrollTop = pdfContainer.scrollTop+100;
  89. const pageHeight = pdfContainer.scrollHeight / scaleData.numPages;
  90. const currentPage = Math.floor(scrollTop / pageHeight) + 1;
  91. scaleData.pageNum = currentPage;
  92. };
  93. onMounted(() => {
  94. setTimeout(() => {
  95. isToolVisible.value = true;
  96. }, 1000);
  97. })
  98. </script>
  99. <style scoped>
  100. .page-tool2 {
  101. position: absolute;
  102. bottom: 18%;
  103. padding-left: 10px;
  104. padding-right: 10px;
  105. align-items: center;
  106. background: rgba(3, 67, 109, 0.075);
  107. color: rgba(2, 1, 41, 0.507);
  108. border-radius: 19px;
  109. z-index: 100;
  110. cursor: pointer;
  111. margin-left: 80%;
  112. margin-right:50px; /* 修改这里 */
  113. }
  114. .page-tool {
  115. position: absolute;
  116. bottom: 25%;
  117. padding-left: 15px;
  118. padding-right: 15px;
  119. align-items: center;
  120. background: rgba(3, 67, 109, 0.075);
  121. color: rgba(2, 1, 41, 0.507);
  122. border-radius: 19px;
  123. z-index: 100;
  124. cursor: pointer;
  125. margin-left: 80%;
  126. margin-right:50px; /* 修改这里 */
  127. }
  128. .page-tool-item {
  129. padding: 20px 15px;
  130. cursor: pointer;
  131. }
  132. .page-tool-item2 {
  133. text-align: center;
  134. padding: 20px 0px;
  135. width: 60px;
  136. cursor: pointer;
  137. white-space: nowrap;
  138. overflow: hidden;
  139. text-overflow: ellipsis;
  140. }
  141. .vue-pdf{
  142. margin: 0px auto;
  143. width: 100%;
  144. position: relative;
  145. overflow: auto;
  146. background: #e3e2e2;
  147. height: 100%;
  148. }
  149. .vue-pdf-cs{
  150. width: 100%;
  151. height: 100%;
  152. text-align: center;
  153. display: flex;
  154. flex-direction: column;
  155. gap: 20px;
  156. }
  157. </style>