pdfPreview.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <template>
  2. <div class="pdf-preview">
  3. <div class="pdf-wrap">
  4. <vue-pdf-embed :source="state.source" :style="scale" class="vue-pdf-embed" :page="state.pageNum" />
  5. </div>
  6. <div class="page-tool">
  7. <div class="page-tool-item" @click="lastPage">上一页</div>
  8. <div class="page-tool-item" @click="nextPage">下一页</div>
  9. <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
  10. <div class="page-tool-item" @click="pageZoomOut">放大</div>
  11. <div class="page-tool-item" @click="pageZoomIn">缩小</div>
  12. </div>
  13. </div>
  14. </template>
  15. <script setup lang="ts">
  16. import VuePdfEmbed from "vue-pdf-embed";
  17. import { createLoadingTask } from "vue3-pdfjs";
  18. import { reactive, onMounted, computed } from "vue";
  19. const props = defineProps({
  20. pdfUrl: {
  21. type: String,
  22. required: true
  23. }
  24. })
  25. const state = reactive({
  26. source: props.pdfUrl,
  27. pageNum: 1,
  28. scale: 1, // 缩放比例
  29. numPages: 0, // 总页数
  30. });
  31. const scale = computed(() => `transform:scale(${state.scale})`)
  32. function lastPage() {
  33. if (state.pageNum > 1) {
  34. state.pageNum -= 1;
  35. }
  36. }
  37. function nextPage() {
  38. if (state.pageNum < state.numPages) {
  39. state.pageNum += 1;
  40. }
  41. }
  42. function pageZoomOut() {
  43. if (state.scale < 2) {
  44. state.scale += 0.1;
  45. }
  46. }
  47. function pageZoomIn() {
  48. if (state.scale > 1) {
  49. state.scale -= 0.1;
  50. }
  51. }
  52. onMounted(() => {
  53. const loadingTask = createLoadingTask(state.source);
  54. loadingTask.promise.then((pdf: { numPages: number }) => {
  55. state.numPages = pdf.numPages;
  56. });
  57. });
  58. </script>
  59. <style lang="css" scoped>
  60. .pdf-preview {
  61. position: relative;
  62. height: 100vh;
  63. padding: 20px 0;
  64. box-sizing: border-box;
  65. background: rgb(66, 66, 66);
  66. }
  67. .vue-pdf-embed {
  68. text-align: center;
  69. width: 515px;
  70. border: 1px solid #e5e5e5;
  71. margin: 0 auto;
  72. box-sizing: border-box;
  73. }
  74. .pdf-preview {
  75. position: relative;
  76. height: 100vh;
  77. padding: 20px 0;
  78. box-sizing: border-box;
  79. background-color: e9e9e9;
  80. }
  81. .pdf-wrap {
  82. overflow-y: auto;
  83. }
  84. .vue-pdf-embed {
  85. text-align: center;
  86. width: 515px;
  87. border: 1px solid #e5e5e5;
  88. margin: 0 auto;
  89. box-sizing: border-box;
  90. }
  91. .page-tool {
  92. position: absolute;
  93. bottom: 35px;
  94. padding-left: 15px;
  95. padding-right: 15px;
  96. display: flex;
  97. align-items: center;
  98. background: rgb(66, 66, 66);
  99. color: white;
  100. border-radius: 19px;
  101. z-index: 100;
  102. cursor: pointer;
  103. margin-left: 50%;
  104. transform: translateX(-50%);
  105. }
  106. .page-tool-item {
  107. padding: 8px 15px;
  108. padding-left: 10px;
  109. cursor: pointer;
  110. }
  111. </style>