index.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <template>
  2. <div
  3. class="thumbnail-slide"
  4. :style="{
  5. width: size + 'px',
  6. height: size * 0.5625 + 'px',
  7. }"
  8. >
  9. <!-- viewportRatio -->
  10. <div
  11. class="elements"
  12. :style="{
  13. width: viewportSize + 'px',
  14. height: viewportSize * viewportRatio + 'px',
  15. transform: `scale(${scale})`,
  16. position: 'absolute',
  17. }"
  18. v-if="visible"
  19. >
  20. <div class="background" :style="backgroundStyle"></div>
  21. <ThumbnailElement
  22. v-for="(element, index) in slide.elements"
  23. :key="element.id"
  24. :scale="scale"
  25. :slide="slide"
  26. :elementInfo="element"
  27. :elementIndex="index + 1"
  28. />
  29. <!-- 遮罩层:确保iframe不会阻止缩略图点击事件 -->
  30. <div class="thumbnail-mask" @click="handleMaskClick"></div>
  31. </div>
  32. <div class="placeholder" v-else>{{ lang.ssLoading }}</div>
  33. </div>
  34. </template>
  35. <script lang="ts" setup>
  36. import { computed, provide } from "vue";
  37. import { storeToRefs } from "pinia";
  38. import { useSlidesStore } from "@/store";
  39. import type { Slide } from "@/types/slides";
  40. import { injectKeySlideScale } from "@/types/injectKey";
  41. import useSlideBackgroundStyle from "@/hooks/useSlideBackgroundStyle";
  42. import { lang } from "@/main";
  43. import ThumbnailElement from "./ThumbnailElement.vue";
  44. const props = withDefaults(
  45. defineProps<{
  46. slide: Slide;
  47. size: number;
  48. visible?: boolean;
  49. }>(),
  50. {
  51. visible: true,
  52. }
  53. );
  54. const emit = defineEmits<{
  55. (event: "click"): void;
  56. }>();
  57. // 处理遮罩层点击事件
  58. const handleMaskClick = (e: MouseEvent) => {
  59. e.stopPropagation();
  60. emit("click");
  61. };
  62. const { viewportRatio, viewportSize } = storeToRefs(useSlidesStore());
  63. const background = computed(() => props.slide.background);
  64. const { backgroundStyle } = useSlideBackgroundStyle(background);
  65. const scale = computed(() => props.size / viewportSize.value);
  66. provide(injectKeySlideScale, scale);
  67. </script>
  68. <style lang="scss" scoped>
  69. .thumbnail-slide {
  70. background-color: #fff;
  71. overflow: hidden;
  72. user-select: none;
  73. position: relative;
  74. }
  75. .elements {
  76. transform-origin: 0 0;
  77. }
  78. .background {
  79. width: 100%;
  80. height: 100%;
  81. background-position: center;
  82. position: absolute;
  83. }
  84. .placeholder {
  85. width: 100%;
  86. height: 100%;
  87. display: flex;
  88. justify-content: center;
  89. align-items: center;
  90. }
  91. .thumbnail-mask {
  92. position: absolute;
  93. top: 0;
  94. left: 0;
  95. width: 100%;
  96. height: 100%;
  97. background: transparent;
  98. pointer-events: auto; /* 拦截所有点击事件 */
  99. z-index: 9999; /* 确保在所有元素之上,包括iframe */
  100. cursor: pointer;
  101. }
  102. </style>