Files
riwa-ionic/packages/distribute/components/PWAInstallBanner.vue

118 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
const { t } = useI18n();
const { canInstall, isInstalled, install } = usePWAInstall();
const installing = ref(false);
const dismissed = ref(false);
// 从 localStorage 读取是否已关闭,但只在未安装状态下有效
onMounted(() => {
// 如果应用未安装,检查用户是否之前关闭过横幅
if (!isInstalled.value) {
dismissed.value = localStorage.getItem("pwa-banner-dismissed") === "true";
}
else {
// 如果应用已安装,清除关闭记录(为了卸载后能再次提示)
localStorage.removeItem("pwa-banner-dismissed");
}
});
// 监听安装状态变化
watch(isInstalled, (newValue) => {
if (newValue) {
// 应用安装后,清除关闭记录
localStorage.removeItem("pwa-banner-dismissed");
dismissed.value = false;
}
});
// 监听 canInstall 变化(卸载后会重新触发 beforeinstallprompt
watch(canInstall, (newValue) => {
if (newValue && !isInstalled.value) {
// 如果可以安装且未安装,清除之前的关闭记录
// 这样卸载后再次访问就会重新显示横幅
localStorage.removeItem("pwa-banner-dismissed");
dismissed.value = false;
}
});
async function handleInstall() {
installing.value = true;
try {
const success = await install();
if (success) {
console.log("PWA 安装成功");
}
}
finally {
installing.value = false;
}
}
function dismissBanner() {
dismissed.value = true;
localStorage.setItem("pwa-banner-dismissed", "true");
}
const showBanner = computed(() => canInstall.value && !isInstalled.value && !dismissed.value);
</script>
<template>
<Transition
enter-active-class="transition-all duration-300 ease-out"
enter-from-class="opacity-0 transform translate-y-4"
enter-to-class="opacity-100 transform translate-y-0"
leave-active-class="transition-all duration-200 ease-in"
leave-from-class="opacity-100 transform translate-y-0"
leave-to-class="opacity-0 transform translate-y-4"
>
<UCard
v-if="showBanner"
class="relative overflow-hidden border-2 border-primary-500/20 shadow-xl shadow-primary-500/10"
>
<!-- 背景装饰 -->
<div class="absolute inset-0 bg-linear-to-br from-primary-50/80 via-blue-50/50 to-purple-50/80 dark:from-primary-950/50 dark:via-blue-950/30 dark:to-purple-950/50" />
<div class="absolute top-0 right-0 w-64 h-64 bg-primary-500/10 rounded-full blur-3xl" />
<div class="absolute bottom-0 left-0 w-64 h-64 bg-purple-500/10 rounded-full blur-3xl" />
<!-- 内容 -->
<div class="relative z-10 flex items-center gap-4">
<!-- 图标 -->
<div class="hidden sm:flex shrink-0 size-16 rounded-2xl bg-linear-to-br from-primary-500 to-primary-600 items-center justify-center text-white text-2xl font-bold shadow-lg shadow-primary-500/30">
<UIcon name="i-heroicons-arrow-down-tray" class="w-8 h-8" />
</div>
<!-- 文字内容 -->
<div class="flex-1 min-w-0">
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-1">
{{ t('installPWA') }}
</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ t('installDesc') }}
</p>
</div>
<!-- 按钮组 -->
<div class="flex items-center gap-2 shrink-0">
<UButton
:loading="installing"
size="lg"
color="primary"
icon="i-heroicons-arrow-down-tray"
class="shadow-lg shadow-primary-500/30"
@click="handleInstall"
>
{{ t('installPWA') }}
</UButton>
<UButton
icon="i-heroicons-x-mark"
color="neutral"
variant="ghost"
size="lg"
@click="dismissBanner"
/>
</div>
</div>
</UCard>
</Transition>
</template>