Loader.vue 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <div
  3. class="loader-wrapper"
  4. :class="{ loaded: !loading, mask: maskReadyRef }"
  5. :style="visibleStyle"
  6. @touchmove.prevent
  7. @mousewheel.prevent
  8. >
  9. <div class="loader">
  10. <p class="tip">{{tip}}</p>
  11. <p class="percent">{{percent}}%</p>
  12. <p class="progress">
  13. <div :style="progressStyle"></div>
  14. </p>
  15. </div>
  16. <!-- <div class="loader-section section-top"></div>
  17. <div class="loader-section section-bottom"></div> -->
  18. <MaskVue ref="maskRef" @end="onEnd"/>
  19. <audio :src="entranceAudio" style="max-width: 1px;max-height: 1px;" ref="entranceAudioRef" ></audio>
  20. </div>
  21. </template>
  22. <script setup>
  23. import { computed, onMounted, ref, watch } from "vue"
  24. import MaskVue from "./Mask.vue";
  25. const entranceAudio = './audios/entrance.mp3';
  26. const props = defineProps({
  27. tip: {
  28. type: String,
  29. default: 'loading...'
  30. },
  31. percent: {
  32. type: Number,
  33. default: 0
  34. },
  35. loading: Boolean
  36. })
  37. const elRef = ref();
  38. const maskRef = ref();
  39. const maskReadyRef = ref(false);
  40. const progressStyle = computed(() => ({ width: `${props.percent}%` }));
  41. const visibleStyle = ref({})
  42. const entranceAudioRef = ref()
  43. const entranceAudioReady = ref(false)
  44. const onEnd = () => {
  45. visibleStyle.value = { display: 'none' }
  46. }
  47. const onTouchMove = (e) => {
  48. // 禁止滚动
  49. e.preventDefault();
  50. }
  51. const playMask = () => {
  52. if (maskReadyRef.value && entranceAudioReady.value) {
  53. entranceAudioRef.value.play();
  54. maskRef.value.start();
  55. }
  56. }
  57. watch(() => props.loading, (newVal, oldVal) => {
  58. if (oldVal && !newVal) {
  59. maskReadyRef.value = true;
  60. playMask();
  61. }
  62. })
  63. onMounted(() => {
  64. document.addEventListener("WeixinJSBridgeReady", function () {
  65. entranceAudioReady.value = true;
  66. playMask();
  67. }, false);
  68. })
  69. </script>
  70. <style lang="less" scoped>
  71. @bg-color: #D7DDD3;
  72. @tip-color: #933D33;
  73. @text-color: #fff;
  74. .loader-wrapper {
  75. position: fixed;
  76. top: 0;
  77. left: 0;
  78. width: 100%;
  79. height: 100%;
  80. z-index: 100;
  81. overflow: hidden;
  82. background: @bg-color;
  83. .loader {
  84. display: block;
  85. position: relative;
  86. z-index: 11;
  87. color: @tip-color;
  88. font-size: 2em;
  89. text-align: center;
  90. padding-top: 200px;
  91. .percent {
  92. color: @text-color;
  93. }
  94. .progress {
  95. box-sizing: border-box;
  96. padding: 0 2em;
  97. & > div {
  98. width: 0%;
  99. height: 2px;
  100. background: @tip-color;
  101. border-radius: 50%;
  102. }
  103. }
  104. }
  105. .loader-section {
  106. position: fixed;
  107. left: 0;
  108. width: 100%;
  109. height: 51%;
  110. background: @bg-color;
  111. z-index: 10;
  112. }
  113. .section-top {
  114. top: 0;
  115. }
  116. .section-bottom {
  117. bottom: 0;
  118. }
  119. &.loaded.mask {
  120. // visibility: hidden;
  121. // transform: translateX(-100%);
  122. // transition: all 0.3s 1s ease-out;
  123. .loader {
  124. opacity: 0;
  125. transition: all 0.3s ease-out;
  126. }
  127. .section-top {
  128. transform: translateY(-100%);
  129. transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
  130. }
  131. .section-bottom {
  132. transform: translateY(100%);
  133. transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
  134. }
  135. }
  136. }
  137. </style>