Main.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <template>
  2. <LoginLayout>
  3. <!-- 背景 -->
  4. <template #background>
  5. <div class="login-bg"></div>
  6. <!-- 漂浮闪烁点 -->
  7. <div class="spark-layer" aria-hidden="true">
  8. <span v-for="d in dots" :key="d.id" class="spark" :style="dotStyle(d)" />
  9. </div>
  10. </template>
  11. <template #main>
  12. <BottomDock mode="ellipse" :auto-hide="false" :custom-class="['dock-style']" :auto-rotate="true"></BottomDock>
  13. </template>
  14. </LoginLayout>
  15. </template>
  16. <script>
  17. import LoginLayout from "@/layouts/LoginLayout.vue";
  18. import BottomDock from "@/components/ui/BottomDock.vue";
  19. export default {
  20. name: "MainPage",
  21. components: {
  22. LoginLayout,
  23. BottomDock
  24. },
  25. created() {
  26. },
  27. data() {
  28. return {
  29. // 亮点
  30. dots: [],
  31. };
  32. },
  33. mounted() {
  34. this.updateScale();
  35. window.addEventListener("resize", this.updateScale, { passive: true });
  36. this.initDots();
  37. },
  38. beforeDestroy() {
  39. window.removeEventListener("resize", this.updateScale);
  40. },
  41. methods: {
  42. updateScale() {
  43. const w = window.innerWidth || this.baseW;
  44. const h = window.innerHeight || this.baseH;
  45. // 取 min 保证不裁切(大屏常见)
  46. this.scale = Math.min(w / this.baseW, h / this.baseH);
  47. // 写到 css 变量,方便 calc(var(--s) * xxxpx)
  48. this.$el && this.$el.style.setProperty("--s", this.scale.toFixed(6));
  49. },
  50. // ---------- 闪烁点 ----------
  51. initDots() {
  52. const count = 50;
  53. const arr = [];
  54. for (let i = 0; i < count; i++) {
  55. arr.push({
  56. id: i,
  57. x: 18 + Math.random() * 64, // 百分比布局,适配任意屏幕
  58. y: 22 + Math.random() * 56,
  59. r: 1.2 + Math.random() * 2.8, // 半径
  60. a: 0.45 + Math.random() * 0.55,
  61. d: Math.random() * 2.8, // delay
  62. t: 1.8 + Math.random() * 2.6, // duration
  63. });
  64. }
  65. this.dots = arr;
  66. },
  67. dotStyle(d) {
  68. return {
  69. left: d.x + "%",
  70. top: d.y + "%",
  71. width: `${d.r * 4}px`,
  72. height: `${d.r * 4}px`,
  73. opacity: d.a,
  74. animationDelay: `${d.d}s`,
  75. animationDuration: `${d.t}s`,
  76. };
  77. },
  78. }
  79. }
  80. </script>
  81. <style scoped>
  82. .dock-style {
  83. left: 0;
  84. bottom: unset !important;
  85. height: 100%;
  86. margin: auto 0;
  87. border-radius: calc(var(--s) * 1.125rem);
  88. background: linear-gradient(180deg, rgba(10, 35, 70, .18), rgba(0, 0, 0, .08));
  89. box-shadow: 0 0 calc(var(--s) * 1.625rem) rgba(0, 140, 255, .08) inset;
  90. backdrop-filter: blur(.125rem);
  91. }
  92. .dock-style ::v-deep .right-arrow {
  93. margin-left: 100px;
  94. }
  95. .dock-style ::v-deep .left-arrow {
  96. margin-right: 100px;
  97. }
  98. .main-page {
  99. position: relative;
  100. width: 100vw;
  101. height: 100vh;
  102. overflow: hidden;
  103. --s: 1;
  104. color: #d9efff;
  105. user-select: none;
  106. }
  107. .login-bg {
  108. background: url('@/assets/images/main-background.png') no-repeat center/cover;
  109. width: 100%;
  110. height: 100%;
  111. filter: saturate(1.05) contrast(1.03);
  112. }
  113. /* 闪烁亮点 */
  114. .spark-layer {
  115. position: absolute;
  116. inset: 0;
  117. z-index: 4;
  118. pointer-events: none;
  119. width: 100%;
  120. height: 100%;
  121. }
  122. .spark {
  123. position: absolute;
  124. border-radius: 999px;
  125. background: radial-gradient(circle, rgba(140, 235, 255, .95), rgba(140, 235, 255, 0) 70%);
  126. animation-name: twinkle;
  127. animation-timing-function: ease-in-out;
  128. animation-iteration-count: infinite;
  129. }
  130. @keyframes twinkle {
  131. 0% {
  132. transform: translateZ(0) scale(.7);
  133. opacity: .22;
  134. }
  135. 50% {
  136. transform: translateZ(0) scale(1.25);
  137. opacity: .9;
  138. }
  139. 100% {
  140. transform: translateZ(0) scale(.7);
  141. opacity: .22;
  142. }
  143. }
  144. </style>