Commit fbb07e1f by lijiabin

【需求 21096】 feat: 优化进度条

parent d375ee1a
<template> <template>
<Progress />
<Notivue v-slot="item"> <Notivue v-slot="item">
<NotivueSwipe :item="item"> <NotivueSwipe :item="item">
<Notification :item="item" :theme="pastelTheme"> </Notification> <Notification :item="item" :theme="pastelTheme"> </Notification>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
import zhCn from 'element-plus/es/locale/lang/zh-cn' import zhCn from 'element-plus/es/locale/lang/zh-cn'
import { initWxConfig } from '@/utils/wxUtil/initWXConfig' import { initWxConfig } from '@/utils/wxUtil/initWXConfig'
import { Notivue, NotivueSwipe, Notification, pastelTheme } from 'notivue' import { Notivue, NotivueSwipe, Notification, pastelTheme } from 'notivue'
import Progress from '@/components/common/Progress/index.vue'
const locale = ref(zhCn) const locale = ref(zhCn)
......
<template>
<Teleport to="body">
<!-- 整条(含主条)一起显隐,避免 finish 后先把 visible 关掉但主条仍显示,percent 归零时出现 100→0 的 width 过渡 -->
<div
v-show="pageProgressVisible"
class="pointer-events-none fixed left-0 right-0 top-0 z-[10000] h-3px overflow-hidden"
role="progressbar"
:aria-hidden="!pageProgressVisible"
:aria-valuenow="clamped"
aria-valuemin="0"
aria-valuemax="100"
>
<!-- 轨道微光 -->
<div class="absolute inset-0 bg-gradient-to-b from-white/25 to-transparent opacity-40"></div>
<!-- 主进度条 -->
<div
class="page-progress-bar relative h-full origin-left rounded-r-full shadow-[0_0_14px_rgba(99,102,241,0.55)]"
:style="barStyle"
>
<!-- 流光 -->
<div class="absolute inset-0 overflow-hidden rounded-r-full" aria-hidden="true">
<div
class="page-progress-shimmer absolute inset-y-0 w-[40%] -skew-x-[20deg] bg-gradient-to-r from-transparent via-white/35 to-transparent"
/>
</div>
</div>
</div>
</Teleport>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import {
finishPageProgress,
pageProgressPercent,
pageProgressVisible,
startPageProgress,
} from './usePageProgress'
const clamped = computed(() => Math.min(100, Math.max(0, Math.round(pageProgressPercent.value))))
const barStyle = computed(() => ({
width: `${clamped.value}%`,
transition:
pageProgressPercent.value >= 100
? 'width 0.22s cubic-bezier(0.22, 1, 0.36, 1)'
: 'width 0.2s ease-out',
}))
defineExpose({
start: startPageProgress,
finish: finishPageProgress,
})
</script>
<style scoped>
.page-progress-bar {
background: linear-gradient(90deg, #6366f1 0%, #8b5cf6 45%, #22d3ee 100%);
}
.page-progress-shimmer {
animation: page-progress-shimmer 1.25s ease-in-out infinite;
}
@keyframes page-progress-shimmer {
0% {
transform: translateX(-120%) skewX(-20deg);
}
100% {
transform: translateX(320%) skewX(-20deg);
}
}
</style>
// 直接把变量写在js文件里面 可以在组件中 或者 其他js文件使用
/** 是否显示顶栏 */
export const pageProgressVisible = ref(false)
/** 0 ~ 100 */
export const pageProgressPercent = ref(0)
let fakeTimer: ReturnType<typeof setInterval> | undefined
let hideTimer: ReturnType<typeof setTimeout> | undefined
function clearTimers() {
if (fakeTimer != null) {
clearInterval(fakeTimer)
fakeTimer = undefined
}
if (hideTimer != null) {
clearTimeout(hideTimer)
hideTimer = undefined
}
}
/** 路由开始时调用:显示并开始「假进度」到 ~88% */
export async function startPageProgress() {
clearTimers()
pageProgressVisible.value = true
pageProgressPercent.value = 0
await nextTick()
pageProgressPercent.value = 12
fakeTimer = setInterval(() => {
if (pageProgressPercent.value < 88) {
pageProgressPercent.value += Math.random() * 12 + 3
if (pageProgressPercent.value > 88) pageProgressPercent.value = 88
}
}, 300)
}
/** 路由结束后调用:拉满并淡出 */
export function finishPageProgress() {
clearTimers()
if (!pageProgressVisible.value) return
pageProgressPercent.value = 100
hideTimer = setTimeout(() => {
pageProgressVisible.value = false
pageProgressPercent.value = 0
}, 450)
}
...@@ -3,14 +3,16 @@ import type { Router } from 'vue-router' ...@@ -3,14 +3,16 @@ import type { Router } from 'vue-router'
import { saveScrollPosition } from './scrollStorage' import { saveScrollPosition } from './scrollStorage'
import { parseCode } from '@/utils/wxUtil' import { parseCode } from '@/utils/wxUtil'
import { useUserStore } from '@/stores' import { useUserStore } from '@/stores'
import { finishPageProgress, startPageProgress } from '@/components/common/Progress/usePageProgress'
// 白名单 // 白名单
const WHITE_LIST: string[] = ['/aa'] const WHITE_LIST: string[] = ['/aa']
export function registerRouterGuards(router: Router) { export function registerRouterGuards(router: Router) {
router.beforeEach(async (to, from) => { router.beforeEach(async (to, from) => {
// console.log('to', to) if (to.fullPath !== from.fullPath) {
// console.log('from', from) startPageProgress()
}
// 保存当前页面的滚动位置 // 保存当前页面的滚动位置
if (from.fullPath) { if (from.fullPath) {
saveScrollPosition(from.fullPath, window.scrollY) saveScrollPosition(from.fullPath, window.scrollY)
...@@ -24,13 +26,10 @@ export function registerRouterGuards(router: Router) { ...@@ -24,13 +26,10 @@ export function registerRouterGuards(router: Router) {
// code是否来自企业微信 1 不是 0 是 2 开发人员登录方式 // code是否来自企业微信 1 不是 0 是 2 开发人员登录方式
// const isCodeLogin = parseIsCodeLogin() // const isCodeLogin = parseIsCodeLogin()
// const cutEmail = parseIsCutEmail() // const cutEmail = parseIsCutEmail()
// console.log(code, isCodeLogin, cutEmail)
const userStore = useUserStore() const userStore = useUserStore()
if (code) { if (code) {
// 如果有token 就不需要重新获取用户信息 // 如果有token 就不需要重新获取用户信息
// console.log('userStore.token', userStore.token)
// if (!userStore.token || !userStore.refreshToken) { // if (!userStore.token || !userStore.refreshToken) {
// console.log('code', code)
await userStore.getUserInfoByCode({ await userStore.getUserInfoByCode({
code, code,
isCodeLogin: 0, isCodeLogin: 0,
...@@ -44,4 +43,12 @@ export function registerRouterGuards(router: Router) { ...@@ -44,4 +43,12 @@ export function registerRouterGuards(router: Router) {
return true return true
} }
}) })
router.afterEach(() => {
finishPageProgress()
})
router.onError(() => {
finishPageProgress()
})
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment