跳至主要內容
Skip to content

呼叫原生分享選單:Web Share API 實戰 ​

在行動網頁上,我們常常看到各種社群媒體的分享按鈕(Facebook, Line, Twitter...)。但這些按鈕往往風格不一,且無法涵蓋使用者所有安裝的 App。

Web Share API 解決了這個問題。它允許網頁像原生 App 一樣,直接呼叫作業系統的「分享選單 (Share Sheet)」。這意味著使用者可以自由選擇將內容分享到 Line、Telegram、AirDrop 或是複製到剪貼簿。


一、 Web Share API 核心 ​

1.1 基本語法 ​

API 掛載於 navigator.share(),它回傳一個 Promise。

javascript
if (navigator.share) {
  navigator.share({
    title: '文章標題',
    text: '這是一篇好文章',
    url: 'https://example.com',
  })
  .then(() => console.log('分享成功'))
  .catch((error) => console.log('分享失敗或取消', error));
}

1.2 關鍵限制 ​

為了安全性與使用者體驗,此 API 有嚴格限制:

  1. HTTPS: 僅限在 HTTPS 環境下運作(localhost 除外)。
  2. 使用者互動: 必須由使用者點擊按鈕等行為觸發,不能自動執行。
  3. 支援度: 主要支援行動裝置瀏覽器(Chrome for Android, Safari on iOS)。桌機版 Chrome/Edge/Safari 近期也已支援,但行為可能不同。

1.3 檔案分享 ​

除了文字與連結,Web Share API Level 2 還支援檔案分享:

javascript
if (navigator.canShare && navigator.canShare({ files: [file] })) {
  navigator.share({
    files: [file],
    title: '分享圖片',
    text: '看看這張照片'
  });
}

二、 封裝 useShare Composable ​

我們將封裝一個 useShare,讓他自動檢測支援度,並提供簡單的呼叫介面。

2.1 介面定義 ​

typescript
export interface ShareOptions {
  title?: string;
  text?: string;
  url?: string;
  files?: File[];
}

export interface UseShareReturn {
  isSupported: boolean;
  canShare: (options: ShareOptions) => boolean;
  share: (options: ShareOptions) => Promise<void>;
}

2.2 完整實作 ​

typescript
// composables/useShare.ts
import { ref } from 'vue';

export function useShare() {
  const isSupported = typeof navigator !== 'undefined' && 'share' in navigator;

  /**
   * 檢查是否支援分享特定的內容
   */
  const canShare = (options: ShareOptions) => {
    if (!isSupported) return false;
    
    // 如果瀏覽器支援 navigator.canShare (Level 2)
    if (typeof navigator.canShare === 'function') {
      return navigator.canShare(options);
    }
    
    // 回退機制:只要有 API 就假設可以分享純文字
    return !options.files; 
  };

  /**
   * 執行分享
   */
  const share = async (options: ShareOptions) => {
    if (!isSupported) {
      throw new Error('Web Share API is not supported');
    }

    try {
      await navigator.share(options);
      return true;
    } catch (err: any) {
      if (err.name === 'AbortError') {
        // 使用者取消分享是正常行為,不視為錯誤
        console.log('使用者取消分享');
        return false;
      }
      throw err;
    }
  };

  return {
    isSupported,
    canShare,
    share
  };
}

三、 實戰範例:分享按鈕元件 ​

這個範例展示一個通用的分享按鈕,如果瀏覽器不支援 Web Share API,則降級為「複製連結」功能。

vue
<script setup lang="ts">
import { useShare } from '@/composables/useShare';
import { useClipboard } from '@/composables/useClipboard'; // 假設前幾章的 Composable

const props = defineProps<{
  title: string;
  url: string;
}>();

const { isSupported, share } = useShare();
const { copy, copied } = useClipboard();

const handleShare = async () => {
  const shareData = {
    title: props.title,
    text: `推薦你閱讀:${props.title}`,
    url: props.url
  };

  if (isSupported) {
    await share(shareData);
  } else {
    // 降級處理:複製連結
    await copy(props.url);
  }
};
</script>

<template>
  <button @click="handleShare" class="share-btn">
    <span v-if="isSupported">
      📲 分享文章
    </span>
    <span v-else>
      {{ copied ? '✅ 已複製' : '🔗 複製連結' }}
    </span>
  </button>
</template>

<style scoped>
.share-btn {
  background: #f0f0f0;
  border: 1px solid #ccc;
  padding: 8px 16px;
  border-radius: 20px;
  cursor: pointer;
  transition: all 0.2s;
}
.share-btn:hover {
  background: #e0e0e0;
}
</style>

四、 測試與除錯 ​

由於 localhost (除了 127.0.0.1) 以外的 HTTP 網域無法使用此 API,建議使用以下方式測試:

  1. 本機測試:直接使用 http://localhost:3000。
  2. 手機測試:使用 ngrok 或類似工具將 localhost 轉發為 HTTPS URL,再用手機開啟。

總結 ​

Web Share API 是提升行動網頁體驗的關鍵拼圖。它讓我們不再需要維護龐大的第三方 SDK,就能提供最原生、最流暢的分享體驗。記得始終提供一個「降級方案」(如複製連結),以確保所有使用者都能分享你的內容。


延伸閱讀 ​