MobilePlayer.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <template>
  2. <div
  3. class="mobile-player"
  4. :style="{
  5. width: playerSize.width + 'px',
  6. height: playerSize.height + 'px',
  7. transform: `rotate(90deg) translateY(-${playerSize.height}px)`,
  8. }"
  9. >
  10. <div
  11. class="screen-slide-list"
  12. @click="toolVisible = !toolVisible"
  13. @touchstart="($event) => touchStartListener($event)"
  14. @touchend="($event) => touchEndListener($event)"
  15. >
  16. <div
  17. :class="[
  18. 'slide-item',
  19. `turning-mode-${slide.turningMode || 'slideY'}`,
  20. {
  21. current: index === slideIndex,
  22. before: index < slideIndex,
  23. after: index > slideIndex,
  24. hide:
  25. (index === slideIndex - 1 || index === slideIndex + 1) &&
  26. slide.turningMode !==
  27. slidesWithTurningMode[slideIndex].turningMode,
  28. last: index === slideIndex - 1,
  29. next: index === slideIndex + 1,
  30. },
  31. ]"
  32. v-for="(slide, index) in slidesWithTurningMode"
  33. :key="slide.id"
  34. >
  35. <div
  36. class="slide-content"
  37. :style="{
  38. width: slideSize.width + 'px',
  39. height: slideSize.height + 'px',
  40. }"
  41. v-if="Math.abs(slideIndex - index) < 2"
  42. >
  43. <ThumbnailSlide :slide="slide" :size="slideSize.width" />
  44. </div>
  45. </div>
  46. </div>
  47. <template v-if="toolVisible">
  48. <div class="header">
  49. <div class="back" @click="changeMode('preview')">
  50. <IconLogout /> 退出播放
  51. </div>
  52. </div>
  53. <MobileThumbnails class="thumbnails" />
  54. </template>
  55. </div>
  56. </template>
  57. <script lang="ts" setup>
  58. import { computed, onMounted, ref } from "vue";
  59. import { storeToRefs } from "pinia";
  60. import { useSlidesStore } from "@/store";
  61. import type { Mode } from "@/types/mobile";
  62. import useSlidesWithTurningMode from "../Screen/hooks/useSlidesWithTurningMode";
  63. import ThumbnailSlide from "@/views/components/ThumbnailSlide/index.vue";
  64. import MobileThumbnails from "./MobileThumbnails.vue";
  65. defineProps<{
  66. changeMode: (mode: Mode) => void;
  67. }>();
  68. const slidesStore = useSlidesStore();
  69. const { slides, slideIndex, viewportRatio } = storeToRefs(slidesStore);
  70. const { slidesWithTurningMode } = useSlidesWithTurningMode();
  71. const toolVisible = ref(false);
  72. const playerSize = ref({ width: 0, height: 0 });
  73. onMounted(() => {
  74. if (slideIndex.value !== 0) slidesStore.updateSlideIndex(0);
  75. playerSize.value = {
  76. width: document.body.clientHeight,
  77. height: document.body.clientWidth,
  78. };
  79. });
  80. const slideSize = computed(() => {
  81. const playerRatio = playerSize.value.height / playerSize.value.width;
  82. let slideWidth = 0;
  83. let slideHeight = 0;
  84. if (playerRatio >= viewportRatio.value) {
  85. slideWidth = playerSize.value.width;
  86. slideHeight = slideWidth * viewportRatio.value;
  87. } else {
  88. slideHeight = playerSize.value.height;
  89. slideWidth = slideHeight / viewportRatio.value;
  90. }
  91. return {
  92. width: slideWidth,
  93. height: slideHeight,
  94. };
  95. });
  96. const touchInfo = ref<{ x: number; y: number } | null>(null);
  97. const touchStartListener = (e: TouchEvent) => {
  98. touchInfo.value = {
  99. x: e.changedTouches[0].pageX,
  100. y: e.changedTouches[0].pageY,
  101. };
  102. };
  103. const touchEndListener = (e: TouchEvent) => {
  104. if (!touchInfo.value) return;
  105. const offsetX = e.changedTouches[0].pageX - touchInfo.value.x;
  106. const offsetY = e.changedTouches[0].pageY - touchInfo.value.y;
  107. const offsetAbsX = Math.abs(offsetX);
  108. const offsetAbsY = Math.abs(offsetY);
  109. if (offsetAbsX > offsetAbsY && offsetAbsX > 50) {
  110. if (offsetX < 0 && slideIndex.value > 0)
  111. slidesStore.updateSlideIndex(slideIndex.value - 1);
  112. if (offsetX > 0 && slideIndex.value < slides.value.length - 1)
  113. slidesStore.updateSlideIndex(slideIndex.value + 1);
  114. }
  115. if (offsetAbsY > offsetAbsX && offsetAbsY > 50) {
  116. if (offsetY > 0 && slideIndex.value > 0)
  117. slidesStore.updateSlideIndex(slideIndex.value - 1);
  118. if (offsetY < 0 && slideIndex.value < slides.value.length - 1)
  119. slidesStore.updateSlideIndex(slideIndex.value + 1);
  120. }
  121. };
  122. </script>
  123. <style lang="scss" scoped>
  124. .mobile-player {
  125. transform-origin: 0 0;
  126. background-color: #1d1d1d;
  127. position: relative;
  128. }
  129. .screen-slide-list {
  130. position: relative;
  131. width: 100%;
  132. height: 100%;
  133. }
  134. .slide-item {
  135. position: absolute;
  136. top: 0;
  137. left: 0;
  138. width: 100%;
  139. height: 100%;
  140. &:not(.last, .next) {
  141. z-index: -1;
  142. }
  143. &.current {
  144. z-index: 2;
  145. }
  146. &.hide {
  147. opacity: 0;
  148. }
  149. &.turning-mode-no {
  150. &.before {
  151. transform: translateY(-100%);
  152. }
  153. &.after {
  154. //transform: translateY(100%);
  155. }
  156. }
  157. &.turning-mode-fade {
  158. transition: opacity 0.75s;
  159. &.before {
  160. pointer-events: none;
  161. opacity: 0;
  162. }
  163. &.after {
  164. pointer-events: none;
  165. opacity: 0;
  166. }
  167. }
  168. &.turning-mode-slideX {
  169. transition: transform 0.35s;
  170. &.before {
  171. transform: translateX(-100%);
  172. }
  173. &.after {
  174. transform: translateX(100%);
  175. }
  176. }
  177. &.turning-mode-slideY {
  178. transition: transform 0.35s;
  179. &.before {
  180. transform: translateY(-100%);
  181. }
  182. &.after {
  183. //transform: translateY(100%);
  184. }
  185. }
  186. }
  187. .slide-content {
  188. background-color: #fff;
  189. position: absolute;
  190. top: 50%;
  191. left: 50%;
  192. transform: translate(-50%, -50%);
  193. display: flex;
  194. justify-content: center;
  195. align-items: center;
  196. }
  197. .header {
  198. width: 100%;
  199. height: 40px;
  200. line-height: 40px;
  201. padding: 0 15px;
  202. position: absolute;
  203. top: 0;
  204. left: 0;
  205. z-index: 99;
  206. background-color: rgba($color: #1d1d1d, $alpha: 0.7);
  207. text-align: right;
  208. font-size: 13px;
  209. color: #fff;
  210. animation: slideInDown 0.15s;
  211. .back {
  212. height: 100%;
  213. }
  214. }
  215. .thumbnails {
  216. width: 100%;
  217. position: absolute;
  218. bottom: 0;
  219. left: 0;
  220. z-index: 99;
  221. background-color: rgba($color: #1d1d1d, $alpha: 0.7);
  222. overflow: auto !important;
  223. animation: slideInUp 0.15s;
  224. }
  225. @keyframes slideInUp {
  226. from {
  227. //transform: translateY(100%);
  228. }
  229. to {
  230. transform: translateY(0);
  231. }
  232. }
  233. @keyframes slideInDown {
  234. from {
  235. transform: translateY(-100%);
  236. }
  237. to {
  238. transform: translateY(0);
  239. }
  240. }
  241. </style>