feat(login): 添加视频背景组件并更新登录页面
在登录页面中新增VideoBackground组件,提供视频背景功能 当视频不可用时自动降级为图片背景 同时更新页面标题为'登陆'
Showing
3 changed files
with
134 additions
and
3 deletions
| ... | @@ -93,6 +93,7 @@ declare module 'vue' { | ... | @@ -93,6 +93,7 @@ declare module 'vue' { |
| 93 | VanTag: typeof import('vant/es')['Tag'] | 93 | VanTag: typeof import('vant/es')['Tag'] |
| 94 | VanTimePicker: typeof import('vant/es')['TimePicker'] | 94 | VanTimePicker: typeof import('vant/es')['TimePicker'] |
| 95 | VanUploader: typeof import('vant/es')['Uploader'] | 95 | VanUploader: typeof import('vant/es')['Uploader'] |
| 96 | + VideoBackground: typeof import('./components/ui/VideoBackground.vue')['default'] | ||
| 96 | VideoPlayer: typeof import('./components/ui/VideoPlayer.vue')['default'] | 97 | VideoPlayer: typeof import('./components/ui/VideoPlayer.vue')['default'] |
| 97 | WechatPayment: typeof import('./components/payment/WechatPayment.vue')['default'] | 98 | WechatPayment: typeof import('./components/payment/WechatPayment.vue')['default'] |
| 98 | } | 99 | } | ... | ... |
src/components/ui/VideoBackground.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-12-26 14:15:46 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-12-26 14:35:49 | ||
| 5 | + * @FilePath: /mlaj/src/components/ui/VideoBackground.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="video-background fixed top-0 left-0 w-full h-full -z-10 overflow-hidden"> | ||
| 10 | + <!-- 优先显示传入的静态图片背景 --> | ||
| 11 | + <div v-if="backgroundImage" class="w-full h-full bg-cover bg-center bg-no-repeat" | ||
| 12 | + :style="{ backgroundImage: `url(${backgroundImage})` }"> | ||
| 13 | + </div> | ||
| 14 | + | ||
| 15 | + <template v-else> | ||
| 16 | + <video v-show="!use_image_bg" ref="videoPlayer" autoplay muted loop playsinline webkit-playsinline | ||
| 17 | + preload="auto" @error="on_video_error" @stalled="on_video_error" @abort="on_video_error" | ||
| 18 | + @emptied="on_video_error" @loadeddata="on_video_loaded" class="w-full h-full object-cover"> | ||
| 19 | + <source :src="videoUrl" type="video/mp4" /> | ||
| 20 | + Your browser does not support the video tag. | ||
| 21 | + </video> | ||
| 22 | + | ||
| 23 | + <!-- 图片降级背景(视频不可用时显示) --> | ||
| 24 | + <StarryBackground v-if="use_image_bg" /> | ||
| 25 | + </template> | ||
| 26 | + | ||
| 27 | + <!-- 遮罩层,确保内容可读性 --> | ||
| 28 | + <div class="absolute inset-0 bg-black/30"></div> | ||
| 29 | + </div> | ||
| 30 | +</template> | ||
| 31 | + | ||
| 32 | +<script setup> | ||
| 33 | +import { ref, onMounted } from 'vue' | ||
| 34 | +/** | ||
| 35 | + * 视频背景组件 | ||
| 36 | + * @description 循环播放指定的视频作为背景 | ||
| 37 | + */ | ||
| 38 | +const props = defineProps({ | ||
| 39 | + videoUrl: { | ||
| 40 | + type: String, | ||
| 41 | + default: 'https://cdn.ipadbiz.cn/mlaj/recall/video/jimeng-2025-12-26-3484.mp4' | ||
| 42 | + }, | ||
| 43 | + backgroundImage: { | ||
| 44 | + type: String, | ||
| 45 | + // TODO: 图片是假的, 如果是真实情况需要重新弄一张正式图片 | ||
| 46 | + default: 'https://cdn.ipadbiz.cn/stdj/images/%E5%90%AF%E5%8A%A8%E9%A1%B5%E6%B5%B7%E6%8A%A5%E8%83%8C%E6%99%AF@2x.png?imageMogr2/thumbnail/400x/strip/quality/70' | ||
| 47 | + } | ||
| 48 | +}) | ||
| 49 | + | ||
| 50 | +const videoPlayer = ref(null) | ||
| 51 | +const use_image_bg = ref(false) | ||
| 52 | +const is_video_ready = ref(false) | ||
| 53 | + | ||
| 54 | +onMounted(() => { | ||
| 55 | + // 如果有传入背景图,则不执行视频逻辑 | ||
| 56 | + if (props.backgroundImage) return | ||
| 57 | + | ||
| 58 | + const video = videoPlayer.value | ||
| 59 | + if (video) { | ||
| 60 | + // 尝试播放视频 | ||
| 61 | + const playPromise = video.play() | ||
| 62 | + | ||
| 63 | + if (playPromise !== undefined) { | ||
| 64 | + playPromise.catch(error => { | ||
| 65 | + // 自动播放被阻止:在微信环境下尝试通过 WeixinJSBridge 播放 | ||
| 66 | + // 说明:避免控制台输出引起诊断问题 | ||
| 67 | + void error | ||
| 68 | + const ua = navigator.userAgent.toLowerCase() | ||
| 69 | + if (ua.match(/MicroMessenger/i) && typeof window.WeixinJSBridge !== 'undefined') { | ||
| 70 | + window.WeixinJSBridge.invoke('getNetworkType', {}, () => { | ||
| 71 | + video.play() | ||
| 72 | + }) | ||
| 73 | + } | ||
| 74 | + // 若短时间内仍无法播放,降级为图片背景,避免黑屏 | ||
| 75 | + setTimeout(() => { | ||
| 76 | + if (!is_video_ready.value) { | ||
| 77 | + enable_image_fallback() | ||
| 78 | + } | ||
| 79 | + }, 1200) | ||
| 80 | + }) | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // 监听微信JSBridgeReady事件 | ||
| 84 | + document.addEventListener('WeixinJSBridgeReady', () => { | ||
| 85 | + video.play() | ||
| 86 | + }, false) | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + // 兜底:在一定时间内仍未加载完成则切换到图片背景 | ||
| 90 | + // setTimeout(() => { | ||
| 91 | + // if (!is_video_ready.value) { | ||
| 92 | + // enable_image_fallback() | ||
| 93 | + // } | ||
| 94 | + // }, 5000) | ||
| 95 | +}) | ||
| 96 | + | ||
| 97 | +/** | ||
| 98 | + * 视频加载成功回调 | ||
| 99 | + * 说明:标记视频已可播放,用于取消降级处理 | ||
| 100 | + */ | ||
| 101 | +const on_video_loaded = () => { | ||
| 102 | + is_video_ready.value = true | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +/** | ||
| 106 | + * 视频错误回调 | ||
| 107 | + * 说明:视频加载/播放失败时触发图片降级,避免黑屏 | ||
| 108 | + * @param {Event} e 事件对象 | ||
| 109 | + */ | ||
| 110 | +const on_video_error = (e) => { | ||
| 111 | + void e | ||
| 112 | + enable_image_fallback() | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +/** | ||
| 116 | + * 启用图片降级背景 | ||
| 117 | + * 说明:切换到全屏图片背景,保证用户视觉不出现黑屏 | ||
| 118 | + */ | ||
| 119 | +const enable_image_fallback = () => { | ||
| 120 | + use_image_bg.value = true | ||
| 121 | +} | ||
| 122 | +</script> | ||
| 123 | + | ||
| 124 | +<style scoped> | ||
| 125 | +.video-background { | ||
| 126 | + /* 确保在所有内容之下 */ | ||
| 127 | + z-index: -1; | ||
| 128 | +} | ||
| 129 | +</style> |
| 1 | <template> | 1 | <template> |
| 2 | <div class="recall-login w-full min-h-screen relative overflow-hidden flex flex-col items-center"> | 2 | <div class="recall-login w-full min-h-screen relative overflow-hidden flex flex-col items-center"> |
| 3 | - <!-- Starry Background Effect --> | 3 | + <!-- <VideoBackground /> --> |
| 4 | <StarryBackground /> | 4 | <StarryBackground /> |
| 5 | 5 | ||
| 6 | - <!-- Title Section --> | 6 | + <!-- 标题区域 --> |
| 7 | <div class="mt-10 flex flex-col items-center z-10 w-full px-8"> | 7 | <div class="mt-10 flex flex-col items-center z-10 w-full px-8"> |
| 8 | <img :src="titleImg" class="w-full max-w-[300px] mb-4 object-contain" alt="title" /> | 8 | <img :src="titleImg" class="w-full max-w-[300px] mb-4 object-contain" alt="title" /> |
| 9 | 9 | ||
| ... | @@ -89,6 +89,7 @@ import { useRouter, useRoute } from 'vue-router' | ... | @@ -89,6 +89,7 @@ import { useRouter, useRoute } from 'vue-router' |
| 89 | import { showToast } from 'vant' | 89 | import { showToast } from 'vant' |
| 90 | import { useTitle } from '@vueuse/core' | 90 | import { useTitle } from '@vueuse/core' |
| 91 | import { setAuthHeaders } from "@/utils/axios"; | 91 | import { setAuthHeaders } from "@/utils/axios"; |
| 92 | +import VideoBackground from '@/components/ui/VideoBackground.vue' | ||
| 92 | 93 | ||
| 93 | // 导入接口 | 94 | // 导入接口 |
| 94 | import { smsAPI } from '@/api/common' | 95 | import { smsAPI } from '@/api/common' |
| ... | @@ -100,7 +101,7 @@ const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title01@2x.png' | ... | @@ -100,7 +101,7 @@ const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title01@2x.png' |
| 100 | // 路由相关 | 101 | // 路由相关 |
| 101 | const $route = useRoute() | 102 | const $route = useRoute() |
| 102 | const $router = useRouter() | 103 | const $router = useRouter() |
| 103 | -useTitle($route.meta.title) | 104 | +useTitle('登陆') |
| 104 | 105 | ||
| 105 | // TAG: 埋点 | 106 | // TAG: 埋点 |
| 106 | const { trackPageView, trackClick } = useTracking() | 107 | const { trackPageView, trackClick } = useTracking() | ... | ... |
-
Please register or login to post a comment