Files
guanwang/app/app.vue

45 lines
1.7 KiB
Vue

<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()
const scrollProgress = ref(0)
let scrollFrame = 0
const canonical = computed(() => `${String(config.public.siteUrl).replace(/\/$/, '')}${route.path === '/' ? '/' : route.path}`)
const isDraftPreview = computed(() => route.query.preview === 'draft')
useHead(() => route.path.startsWith('/admin') ? {} : {
link: [{ rel: 'canonical', href: canonical.value }],
})
useSeoMeta({ ogUrl: () => canonical.value, twitterCard: 'summary_large_image' })
const updateScrollProgress = () => {
scrollFrame = 0
const max = document.documentElement.scrollHeight - window.innerHeight
scrollProgress.value = max > 0 ? Math.min(1, window.scrollY / max) : 0
}
const requestProgressUpdate = () => {
if (!scrollFrame) scrollFrame = requestAnimationFrame(updateScrollProgress)
}
onMounted(() => {
updateScrollProgress()
window.addEventListener('scroll', requestProgressUpdate, { passive: true })
window.addEventListener('resize', requestProgressUpdate, { passive: true })
})
onBeforeUnmount(() => {
if (import.meta.client) {
window.removeEventListener('scroll', requestProgressUpdate)
window.removeEventListener('resize', requestProgressUpdate)
}
if (scrollFrame) cancelAnimationFrame(scrollFrame)
})
</script>
<template>
<NuxtRouteAnnouncer />
<a class="skip-link" href="#main-content">跳到正文</a>
<div v-if="!route.path.startsWith('/admin')" class="page-progress" aria-hidden="true"><span :style="{ transform: `scaleX(${scrollProgress})` }" /></div>
<div v-if="isDraftPreview" class="draft-preview-ribbon"><strong>草稿预览</strong><span>此页面不会被搜索引擎收录</span><NuxtLink to="/admin">返回后台</NuxtLink></div>
<NuxtPage />
</template>