SwAddToHomescreenGuide

H5 行動端使用者首次造訪 PWA 專案時,從螢幕底部滑入一張非阻斷式資訊卡片,引導使用者把站點儲存到主畫面。 iOS Safari 和 Android 主流 Chromium 瀏覽器(Chrome / Edge / Samsung Internet / Firefox / Opera)分別給出對應步驟; 其它環境(桌面 / WebView / iOS 非 Safari / 區域型瀏覽器等)一律靜默不彈出,避免誤導。

元件使用 <Teleport to="body"> + <Transition> 渲染為底部 sheet, 帶半透明遮罩(--sw-add-to-homescreen-guide-backdrop,預設 rgb(0 0 0 / 45%)),但不鎖捲動 / 不搶焦; 關閉方式三選一:右上角 X 按鈕 / 點遮罩 / Escape 鍵。

觸發條件

以下條件全部滿足才顯示:

  1. 客戶端環境(SSR 不會渲染)
  2. PWA 已啟用 —— 執行時判據是 runtimeConfig.public.swiftWebFramework.pwa.enabled === true,它由設定期的 swift.config.json 裡 framework.pwa(布林)派生
  3. framework.addToHomescreen.enabled !== false
  4. 不在 standalone 顯示模式,即使用者尚未把站點加到主畫面。兩條判據缺一不可(fw#352):window.matchMedia('(display-mode: standalone)').matches === false 且 navigator.standalone !== true —— 後者是 iOS 專有屬性,也是 iOS legacy web clip(無 linked manifest 時「加入主畫面」的產物)唯一可靠的訊號,那種形態下媒體查詢並不匹配
  5. 設備類型可明確判定(詳見下方 UA 矩陣)
  6. 使用者最近"沒被記住關閉"(由 rememberFor 決定)
  7. 到點時沒有模態對話框開著(fw#387):判據是 document.body.style.pointerEvents === 'none'——SwModal 底層的 reka-ui Dialog 開啟期間會把 body 設成 pointer-events: none,引導層就算 z-index 更高、看得見,X 與遮罩也點不動。命中則每 500ms 複查,對話框關掉後再彈。業務自帶的年齡確認 / 公告彈窗與引導同屏時尤其常見

PWA 未啟用時的警告:dev 模式下,若元件已掛載但執行時 pwa.enabled === false, 會在 console 輸出一則 warn,提醒開發者要嘛啟用 PWA、要嘛從 app.vue 註解 / 刪除掛載點。

設備 / 瀏覽器支援矩陣

平台瀏覽器是否觸發說明
iOSSafari✓iOS 16+ / 17+ / 26+
iOSChrome / Firefox / Edge✗iOS 系統限制只有 Safari 能加到主畫面
iOSLINE / 其它 WebView✗WebView 無原生入口
AndroidChrome✓Chrome 主流入口
AndroidEdge / Samsung Internet✓同樣支援
AndroidFirefox / Opera✓主流 Chromium 衍生版
AndroidWebView (; wv))✗WebView 無原生入口
AndroidUC / QQ / WeChat / 百度 / MIUI / Vivo / Oppo / Quark / 360 / Sogou✗區域型瀏覽器無 PWA 入口或體驗差
桌面(macOS / Windows / Linux)任意瀏覽器✗桌面端不彈行動端引導

基本用法

demo 數量豁免說明:本元件的完整 UI 僅在 iOS Safari / Android Chromium 且五道閘全過時可見,桌面 docs 站無法演示更多形態(slots 自訂等需真機驗證),故僅保留下方 2 個可運行 demo + 閘門探測。

掛載演示(手機瀏覽器可見引導)

加载中...

當前環境閘門探測(為什麼不彈)

加载中...

framework 預設提供純文字 fallback,開箱即用:

<template>
  <NuxtLayout><NuxtPage /></NuxtLayout>
  <SwModalHost />
  <SwToast />
  <SwAddToHomescreenGuide />
</template>

掛載到 app.vue 與 <SwModalHost />、<SwToast /> 同層即可。framework 在 mount 後 2 秒(預設)滑入引導, 包含 iOS 或 Android 的兩步圖文。

注入圖示庫

framework 不內建圖示 SVG(遵守"不引圖示庫"規範);推薦 applier 透過 slot 注入圖示庫做更豐富的視覺。 以下為 @phosphor-icons/vue 真實範例:

<script setup lang="ts">
import { PhShareNetwork, PhDotsThreeVertical, PhPlusSquare } from '@phosphor-icons/vue'
</script>

<template>
  <SwAddToHomescreenGuide>
    <template #ios-instructions>
      <li>
        <PhShareNetwork :size="20" weight="regular" />
        點擊 Safari 工具列的<strong>「分享」</strong>按鈕
      </li>
      <li>
        <PhPlusSquare :size="20" weight="regular" />
        選擇<strong>「加入主畫面」</strong>並確認
      </li>
    </template>
    <template #android-instructions>
      <li>
        <PhDotsThreeVertical :size="20" weight="regular" />
        點擊瀏覽器右上角的<strong>選單</strong>
      </li>
      <li>
        <PhPlusSquare :size="20" weight="regular" />
        選擇<strong>「加入主畫面」</strong>並確認
      </li>
    </template>
  </SwAddToHomescreenGuide>
</template>

控制彈出頻率

預設每個瀏覽器會話只彈一次(關閉分頁後重置)。如希望"使用者關閉後 N 天內不再打擾",使用 rememberFor prop:

<!-- 一週內不再彈 -->
<SwAddToHomescreenGuide remember-for="7d" />

<!-- 一天內不再彈 -->
<SwAddToHomescreenGuide remember-for="1d" />

<!-- 實質永久(100 年) -->
<SwAddToHomescreenGuide remember-for="36500d" />
rememberFor 值儲存後端行為
'session'(預設)sessionStorage關分頁即重置,下次造訪重彈
正數 NlocalStorage(帶 timestamp)關閉後 N 天內不再彈
0 / 負數不儲存每次造訪都彈(僅供除錯)

自訂視覺

透過 CSS 變數在 applier 一側整體調色:

變數預設值控制
--sw-add-to-homescreen-guide-bgvar(--popover)面板背景色
--sw-add-to-homescreen-guide-accentvar(--primary)步驟序號圓點底色
--sw-add-to-homescreen-guide-accent-foregroundvar(--primary-foreground)步驟序號文字色(與上一條配對,別只改一側)
--sw-add-to-homescreen-guide-backdroprgb(0 0 0 / 45%)遮罩層顏色
--sw-add-to-homescreen-guide-step-bgvar(--muted)單條步驟的底色
--sw-add-to-homescreen-guide-radius1.25rem頂部圓角
--sw-add-to-homescreen-guide-z1100z-index
--sw-add-to-homescreen-guide-close-bgvar(--muted)關閉鈕底色(淡圓底,讓它讀起來像按鈕)
--sw-add-to-homescreen-guide-close-hover-bgvar(--accent)關閉鈕 hover 底色(僅 hover: hover 裝置)
--sw-add-to-homescreen-guide-shadow0 -8px 32px rgb(0 0 0 / 12%)面板投影。向上投影,不套 --shadow-lg(那三檔按向下投影設計)

類別鉤子 .sw-add-to-homescreen-guide(portal 到 body 的根 div)允許深度覆蓋佈局。元件由於 Teleport 到 body, scoped CSS 不可達,需用非 scoped <style> 覆蓋。

<style>
.sw-add-to-homescreen-guide {
  --sw-add-to-homescreen-guide-accent: #ff6b00;
  --sw-add-to-homescreen-guide-radius: 1.25rem;
  border: 4px solid #000 !important;
  box-shadow: 6px 6px 0 0 #000 !important;
}
</style>

專案級設定

除元件 prop 外,可透過 swift.config.json 設定專案級預設(透過 framework module 的 runtimeConfig 傳遞):

{ "framework": { "pwa": true } }

🔴 寫成 { "pwa": { "enabled": true } } 會靜默關閉 PWA。framework 的判據是嚴格 === true(module.ts),物件形態判偽 ⇒ @vite-pwa/nuxt 整個不裝, Service Worker / manifest / 主畫面鏈路全都沒有 —— 效果與寫 "pwa": false 完全相同, 且全程無報錯。sw config set framework.pwa 也會拒絕物件形態(它在 CLI 的布林鍵名單裡)。

引導浮層的行為寫在 nuxt.config.ts(本項不進 swift.config.json,CLI 不管它 —— 它是 framework 的元件行為,不是 manifest 內容):

swiftConfig: {
  ...swiftConfig.framework,
  addToHomescreen: { delay: 3000, rememberFor: '7d' }, // enabled 省略 = 跟随 framework.pwa
},

enabled 可省略,省略時跟隨 framework.pwa(與不傳整個 addToHomescreen 同義), 所以只想改延遲寫 { delay: 3000 } 即可。顯式 enabled: false 可在 PWA 開著時單獨關掉引導。

優先順序:元件 prop > nuxt.config.ts 的 swiftConfig > 內建預設('session' / 2000ms)。

如希望完全停用引導(保留 PWA 但不彈引導):

swiftConfig: { ...swiftConfig.framework, addToHomescreen: false },

Props

名稱類型必填預設值說明
delaynumber2000mount 後多久彈出(毫秒)。優先順序:prop > runtimeConfig > 2000
rememberFor'session' | PeriodSpec'session'記憶關閉狀態多久。'session' = sessionStorage;'Nm'·'Nh'·'Nd' = N 分·時·天內不再彈;'0d' = 不記憶

Slots

插槽名預設渲染說明
iconmanifest 的 /icons/icon-192.png(載入失敗則隱藏)應用圖示
title站點名(project.title),無則回退「儲存到主畫面」彈窗標題
ios-instructionsiOS 三步(前兩步帶內建線性 SVG 圖示)iOS Safari 操作步驟內容
android-instructionsAndroid 三步(前兩步帶內建線性 SVG 圖示)Android Chromium 操作步驟內容

疑難排解

引導沒彈?依下列順序檢查:

  1. swift.config.json 裡 framework.pwa 是否為 true(布林,不是物件)?dev console 應該有對應 warn 幫助定位。寫成 { "enabled": true } 會靜默關閉 PWA,見上「專案級設定」
  2. 是否在客戶端首次造訪?同分頁刷新已彈過的不再彈(除非 rememberFor: 0)
  3. 目前 UA 是否在支援矩陣裡?iOS Chrome / 區域型瀏覽器 / 桌面端都不彈
  4. 是否已"加到主畫面"過?iOS Safari / Android Chrome 加到主畫面後 UA 切到 standalone 模式,元件主動跳過
  5. addToHomescreen.enabled 是否被顯式設為 false?檢查 swift.config.json
  6. rememberFor: N 模式下,localStorage 的 sw:a2hs:dismissedAt 是否還在 N 天視窗內? 清瀏覽器儲存或調小 rememberFor 重新觸發

沒有 live demo:本元件依賴行動端 UA + 真實 PWA 設定,桌面瀏覽器無法觸發,文檔站不提供 DemoBox。 請在真機或 Chrome DevTools「Toggle device toolbar」模擬行動裝置 UA 自行驗證。

注意事項

  • 「怎麼都不彈」先按 5 道靜默閘排查(Rule UAH-001)—— 多數條件不滿足時靜默 return、無任何提示(僅「PWA 未啟用」有 dev warn):① PWA 未啟用 ② addToHomescreen.enabled === false ③ 已在 standalone(在已安裝的 PWA 視窗裡除錯就永遠不彈)④ 裝置非 iOS Safari / Android Chromium(含糊裝置一律靜默)⑤ 處於已記憶的靜默期內。
  • rememberFor 是三態,最容易選錯 —— 正數 N = N 天內不再彈(localStorage 持久);'session' = 關分頁即重置;0 或負數 = 每次都彈(僅測試用)。想「每次進站演示」用了 'session' 會變成一個工作階段只彈一次;想「永久只彈一次」用 'session' 則關頁又彈。常用值是 7。
  • iOS 與 Android 的引導文案 / 圖示不同 —— 元件按裝置分支算繪,除錯時注意 UA 模擬未必能觸發對應分支。