index.vue 2.6 KB

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