index.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <template>
  2. <el-button
  3. v-if="contentType === 'button'"
  4. :type="btnType"
  5. :link="isLink"
  6. @click="showPdf"
  7. >
  8. {{ btnText }}
  9. </el-button>
  10. <VuePdfEmbed
  11. v-else
  12. :source="{ url: pdfSource, cMapUrl: '/cmaps/', cMapPacked: true }"
  13. :page="pageNumber"
  14. annotation-layer
  15. text-layer
  16. @click="showPdf"
  17. />
  18. <el-drawer
  19. v-if="needToShowPdf"
  20. v-model="visible"
  21. :footer="false"
  22. :header="false"
  23. :show-close="false"
  24. destroy-on-close
  25. direction="rtl"
  26. :append-to-body="true"
  27. size="972px"
  28. >
  29. <VuePdfEmbed
  30. :source="{
  31. url: pdfSource,
  32. cMapUrl: '/cmaps/',
  33. cMapPacked: true,
  34. }"
  35. :page="showPdfNumber"
  36. @rendered="rendered"
  37. annotation-layer
  38. text-layer
  39. />
  40. </el-drawer>
  41. </template>
  42. <script setup>
  43. import VuePdfEmbed from "vue-pdf-embed";
  44. // essential styles
  45. import "vue-pdf-embed/dist/style/index.css";
  46. // optional styles
  47. import "vue-pdf-embed/dist/style/annotationLayer.css";
  48. import "vue-pdf-embed/dist/style/textLayer.css";
  49. // either URL, Base64, binary, or document proxy
  50. const props = defineProps({
  51. pdfSource: {
  52. type: String,
  53. required: true,
  54. },
  55. pageNumber: {
  56. type: Number,
  57. default: 0,
  58. },
  59. needToShowPdf: {
  60. type: Boolean,
  61. default: false,
  62. },
  63. contentType: {
  64. type: String,
  65. default: "pdf",
  66. },
  67. btnText: {
  68. type: String,
  69. default: "预览",
  70. },
  71. btnType: {
  72. type: String,
  73. default: "primary",
  74. },
  75. isLink: {
  76. type: Boolean,
  77. default: false,
  78. },
  79. showPdfNumber: {
  80. type: Number,
  81. default: 0,
  82. },
  83. });
  84. const visible = ref(false);
  85. const showPdf = () => {
  86. visible.value = true;
  87. };
  88. const rendered = () => {
  89. const clickableElementsA = document.querySelectorAll(
  90. ".el-drawer__body .vue-pdf-embed div"
  91. );
  92. const clickableElements = document.querySelectorAll(
  93. ".el-drawer__body .vue-pdf-embed .vue-pdf-embed__page"
  94. );
  95. clickableElementsA.forEach((element) => {
  96. element.style.display = "flex";
  97. element.style.alignItems = "center";
  98. element.style.justifyContent = "center";
  99. });
  100. clickableElements.forEach((element, index) => {
  101. let rotationAngle = 0;
  102. element.addEventListener("click", () => {
  103. const currentWidth = element.offsetWidth;
  104. const currentHeight = element.offsetHeight;
  105. const parent = element.parentNode;
  106. let distance = 0;
  107. if (currentHeight > currentWidth) {
  108. distance = currentHeight - currentWidth;
  109. } else {
  110. element.style.width = `${currentHeight}px`;
  111. element.style.height = `${currentWidth}px`;
  112. }
  113. rotationAngle = (rotationAngle + 90) % 360;
  114. if (rotationAngle == 0) {
  115. if (distance > 0) {
  116. element.style.transform = `rotate(${rotationAngle}deg) `;
  117. element.firstElementChild.style.transform = `translateY(0px) `;
  118. } else {
  119. element.style.transform = `rotate(${rotationAngle}deg) `;
  120. element.firstElementChild.style.transform = `translateY(0px) `;
  121. }
  122. }
  123. if (rotationAngle == 90) {
  124. if (distance > 0) {
  125. element.style.transform = `rotate(${rotationAngle}deg)`;
  126. element.firstElementChild.style.transform = `translateY(-${distance / 2}px) `;
  127. } else {
  128. element.style.transform = `rotate(${rotationAngle}deg)`;
  129. element.firstElementChild.style.transform = `translateY(0px) `;
  130. }
  131. }
  132. if (rotationAngle === 180) {
  133. if (distance > 0) {
  134. element.style.transform = `rotate(${rotationAngle}deg) `;
  135. element.firstElementChild.style.transform = `translateY(0px) `;
  136. } else {
  137. element.style.transform = `rotate(${rotationAngle}deg) `;
  138. element.firstElementChild.style.transform = `translateY(0px) `;
  139. }
  140. }
  141. if (rotationAngle === 270) {
  142. if (distance > 0) {
  143. element.style.transform = `rotate(${rotationAngle}deg) `;
  144. element.firstElementChild.style.transform = `translateY(${distance / 2}px) `;
  145. } else {
  146. element.style.transform = `rotate(${rotationAngle}deg) `;
  147. element.firstElementChild.style.transform = `translateY(0px) `;
  148. }
  149. }
  150. parent.style.width = `${currentWidth}px`;
  151. parent.style.height = `${currentHeight}px`;
  152. });
  153. element.addEventListener("wheel", function (event) {
  154. const currentWidth = element.offsetWidth;
  155. const currentHeight = element.offsetHeight;
  156. const parent = element.parentNode;
  157. if (event.ctrlKey) {
  158. event.preventDefault();
  159. // 获取当前的transform值并解析
  160. const transform = getComputedStyle(element).transform;
  161. let scale = 1,
  162. rotate = 0;
  163. if (transform && transform !== "none") {
  164. const transformMatrix = new WebKitCSSMatrix(transform);
  165. scale = Math.sqrt(
  166. Math.pow(transformMatrix.a, 2) + Math.pow(transformMatrix.b, 2)
  167. );
  168. rotate =
  169. Math.atan2(transformMatrix.b, transformMatrix.a) * (180 / Math.PI);
  170. }
  171. // 根据滚轮方向调整缩放级别
  172. if (event.deltaY < 0) {
  173. // 向上滚动,放大
  174. scale += 0.1;
  175. } else {
  176. // 向下滚动,缩小
  177. scale -= 0.1;
  178. }
  179. // 确保缩放级别不会变成负数或过小
  180. scale = Math.max(0.1, Math.min(scale, 5));
  181. // 应用新的缩放级别和原有的旋转角度
  182. element.style.transform = `scale(${scale}) rotate(${rotate}deg)`;
  183. //同步放大展示盒子
  184. parent.style.width = `${currentWidth * scale}px`;
  185. parent.style.height = `${currentHeight * scale}px`;
  186. }
  187. });
  188. });
  189. };
  190. </script>
  191. <style lang="scss" scoped></style>