index.vue 5.5 KB

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