PlayPrompt.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <template>
  2. <div v-if="visible" class="play-prompt-overlay">
  3. <div class="play-prompt-container">
  4. <button class="close-button" @click="handleClose">×</button>
  5. <h3 class="prompt-title">即将跳转下一节</h3>
  6. <div class="countdown-container">
  7. <div class="countdown-circle">
  8. <span class="countdown-number">{{ countdown }}</span>
  9. </div>
  10. </div>
  11. </div>
  12. </div>
  13. </template>
  14. <script setup>
  15. import { ref, onMounted, onUnmounted, watch } from 'vue'
  16. const props = defineProps({
  17. visible: {
  18. type: Boolean,
  19. default: false
  20. },
  21. duration: {
  22. type: Number,
  23. default: 5
  24. },
  25. message: {
  26. type: String,
  27. // default: '准备好开始下一节了吗?'
  28. }
  29. })
  30. const emit = defineEmits(['countdownEnd', 'close'])
  31. const countdown = ref(props.duration)
  32. let countdownTimer = null
  33. const handleClose = () => {
  34. stopCountdown()
  35. emit('close')
  36. }
  37. const startCountdown = () => {
  38. countdown.value = props.duration
  39. if (countdownTimer) {
  40. clearInterval(countdownTimer)
  41. }
  42. countdownTimer = setInterval(() => {
  43. countdown.value--
  44. if (countdown.value <= 0) {
  45. clearInterval(countdownTimer)
  46. emit('countdownEnd')
  47. }
  48. }, 1000)
  49. }
  50. const stopCountdown = () => {
  51. if (countdownTimer) {
  52. clearInterval(countdownTimer)
  53. countdownTimer = null
  54. }
  55. }
  56. watch(() => props.visible, (newVisible) => {
  57. if (newVisible) {
  58. startCountdown()
  59. } else {
  60. stopCountdown()
  61. }
  62. })
  63. onMounted(() => {
  64. if (props.visible) {
  65. startCountdown()
  66. }
  67. })
  68. onUnmounted(() => {
  69. stopCountdown()
  70. })
  71. </script>
  72. <style scoped lang="scss">
  73. @use 'sass:math';
  74. // 定义rpx转换函数
  75. @function rpx($px) {
  76. @return math.div($px, 750) * 100vw;
  77. }
  78. .play-prompt-overlay {
  79. position: fixed;
  80. top: 0;
  81. left: 0;
  82. right: 0;
  83. bottom: 0;
  84. background-color: rgba(0, 0, 0, 0.7);
  85. display: flex;
  86. justify-content: center;
  87. align-items: flex-start;
  88. padding-top: rpx(10);
  89. z-index: 9999;
  90. }
  91. .play-prompt-container {
  92. background: linear-gradient(135deg, #ffffff, #f0f0f0);
  93. border-radius: rpx(10);
  94. padding: rpx(6);
  95. display: flex;
  96. align-items: center;
  97. justify-content: center;
  98. gap: rpx(5);
  99. box-shadow: 0 rpx(10) rpx(20) rgba(0, 0, 0, 0.3);
  100. max-width: 80%;
  101. animation: fadeInScale 0.5s ease-out;
  102. position: relative;
  103. }
  104. .close-button {
  105. width: rpx(10);
  106. height: rpx(10);
  107. border: none;
  108. background: none;
  109. font-size: rpx(10);
  110. font-weight: bold;
  111. display: flex;
  112. align-items: center;
  113. justify-content: center;
  114. cursor: pointer;
  115. z-index: 10;
  116. outline: none;
  117. box-shadow: none;
  118. padding: 0;
  119. margin: 0;
  120. }
  121. .prompt-title {
  122. font-size: rpx(8);
  123. color: #333;
  124. margin: 0;
  125. font-weight: bold;
  126. }
  127. .prompt-message {
  128. font-size: rpx(7);
  129. color: #666;
  130. margin-bottom: rpx(30);
  131. }
  132. .countdown-container {
  133. display: flex;
  134. justify-content: center;
  135. align-items: center;
  136. }
  137. .countdown-circle {
  138. width: rpx(20);
  139. height: rpx(20);
  140. border-radius: 50%;
  141. background: linear-gradient(135deg, #6a5acd, #9370db);
  142. display: flex;
  143. justify-content: center;
  144. align-items: center;
  145. box-shadow: 0 rpx(10) rpx(20) rgba(106, 90, 205, 0.4);
  146. animation: pulse 1s infinite;
  147. }
  148. .countdown-number {
  149. font-size: rpx(10);
  150. font-weight: bold;
  151. color: white;
  152. text-shadow: 0 rpx(2) rpx(4) rgba(0, 0, 0, 0.3);
  153. }
  154. // 动画效果
  155. @keyframes fadeInScale {
  156. from {
  157. opacity: 0;
  158. transform: scale(0.8);
  159. }
  160. to {
  161. opacity: 1;
  162. transform: scale(1);
  163. }
  164. }
  165. @keyframes pulse {
  166. 0% {
  167. transform: scale(1);
  168. }
  169. 50% {
  170. transform: scale(1.05);
  171. }
  172. 100% {
  173. transform: scale(1);
  174. }
  175. }
  176. </style><!-- 即将播放下一节提示 -->