2019年11月20日

[WebAPIs] Web Share API 的使用 - navigator.share

keywords: WebAPIs, mobile, navigator.share

TL;DR

// 判斷瀏覽器是否支援 Web Share API
if (navigator.share) {
  // navigator.share 會回傳 Promise
  navigator.share({
    title: 'Web Fundamentals',
    text: 'Check out Web Fundamentals — it rocks!',
    url: 'https://developers.google.com/web',
  })
  .then(() => console.log('Successful share'))
  .catch((error) => console.log('Error sharing', error));
}

Web Share API 的說明

用手機瀏覽網頁的時候,不知道你有沒有注意過,當你按下分享按鈕時它會跳出一個選單,讓你可以選擇要分享到哪個 App 的選單,像是這樣:
Web Share API
這個功能過去需要透過點擊手機瀏覽器上的「分享」後才會出現:
Web Share API
但現在透過 Web Share 這個 API 也可以輕鬆達到這個功能,讓使用者在點擊網頁上的按鈕後就跳出這個「分享選單」,如此就有機會省去使用那種帶有一堆 Facebook、Line、Twitter、Pinterest 按鈕的第三方套件,進一步減少頁面載入時間。
現在就來看看怎麼使用吧!

Web Share API - navigator.share

適用瀏覽器

Web Share API 的使用方式很簡單,但要注意的是這主要是適用在手機上的功能,畢竟電腦上沒有這種分享選單(目前除了 Mac 的 Safari 可用),不過即使電腦不支援此 API 的使用,還是可以很容易做出替代方案(fallback)。
看到下圖瀏覽器支援性的一大片紅字感覺很恐怖,但目前(2019-11-20)其實主要的手機瀏覽器(Chrome, Safari)都適用,Mac 上的 Safari 亦可:
Web Share API
目前實測在三星內建的瀏覽器上可以使用,但分享成功後的回傳訊息不太正確。

使用方式

使用方式很簡單:
// navigator.share 會回傳一個 Promise

// 下面的欄位可以不用全部填寫,可以只分享網址,也可以只分享文字
const sharePromise = navigator.share({
  url: 'https://pjchender.blogspot.com',    // 要分享的 URL
  title: 'PJCHENder 那些沒告訴你的小細節',      // 要分享的標題
  text: '好多眉眉角角啊'             // 要分享的文字內容
});
navigator.share() 會回傳一個 Promise (代表你可以搭配 async...await 使用),這個 Promise 會在使用者完成點擊某個 App 分享後被完成(fulfilled);若使用者取消分享或帶入的參數有錯誤時,則會被拒絕(reject)。
使用時有幾點需留意一下:
  1. Web Share API 只能使用在有 HTTPS 的網站或者是測試時的 localhost,若想玩玩看這個 API 就可以到帶有 HTTPS 的 CodePen 上試試看。
  2. 需要透過使用者主動的行爲(user activation)才能觸發,例如,點擊事件。

範例程式碼

來看一下範例程式碼吧,也可以直接看 CodePen
See the Pen Web Share API by PJCHEN (@PJCHENder) on CodePen.

HTML

先建立最基本的一個按鈕:
<div class="center-center">
  <button>Share<i class="fas fa-share-alt"></i></button>
  <p class="result"></p>
</div>

JavaScript

  1. 透過 document.querySelector() 選擇和 DOM 有關的元素
  2. 建立使用者點擊分享時要帶入的資訊,不用每一項都填寫,也可以只分享文字或網址
  3. Web Share API 需要使用者主動的行為才能觸發, 所以透過 addEventListener 監聽使用者點擊 click 事件
  4. 透過 navigator.share 來使用 Web Share API
  5. 當使用者拒絕分享或發生錯誤時要顯示的訊息
// STEP 1:選擇和 DOM 有關的元素
const btn = document.querySelector('button');
const result = document.querySelector('.result');

// STEP 2:建立使用者點擊分享時要帶入的資訊
const shareData = {
  url: 'https://pjchender.blogspot.com', // 要分享的 URL
  title: 'PJCHENder 那些沒告訴你的小細節', // 要分享的標題
  text: '好多眉眉角角啊', // 要分享的文字內容
};

// STEP 3:當使用者點擊按鈕時
btn.addEventListener('click', async () => {
  try {
    // STEP 4:使用 Web Share API
    await navigator.share(shareData);
    result.textContent = '感謝你的的分享';
  } catch (err) {
    // STEP 5:使用者拒絕分享或發生錯誤
    const { name, message } = err;
    if (name === 'AbortError') {
      result.textContent = '您已取消分享此訊息';
    } else {
      result.textContent = err;
      console.log('發生錯誤', err);
    }
  }
});
如此就完成這個簡單的範例了。
這個範例的按鈕樣式是修改自 AyooluwaCodePen
來看一下實作的結果:
Web Share API
以 Line 為例,傳送出去的訊息內容如下:
Web Share API
See the Pen Web Share API by PJCHEN (@PJCHENder) on CodePen.

替代處理與其他(fallback)

對於不支援 Web Share API 的瀏覽器則可以透過判斷 navigator.share 是否存在來進行替代方案:
if (navigator.share) {
  // 使用 Web Share API
} else {
  // 替代方案寫在這...
}
舉例來說,在 CSS Tricks 的 How to Use the Web Share API 文章中提供了非常精緻的替代處理畫面:
Imgur
可以參考這個作者的 CodePen 範例。
如果不想這麼複雜的話,替代方案也可以是點擊按鈕後複製網址(Copy Link)給使用者自行分享即可。複製到剪貼簿的方式同樣有對應的 WebAPIs 可以支援,有需要可以參考先前整理的筆記 [WebAPIs] Copy to clipboard 複製到剪貼簿

範例程式碼:當瀏覽器不支援時讓按鈕變成複製功能

這裡提供實際的範例可以作為參考:
// 選擇和 DOM 有關的元素
const btn = document.querySelector('button');
const result = document.querySelector('.result');

// 當使用者點擊分享時要帶入的資訊
const shareData = {
  url: 'https://pjchender.blogspot.com', // 要分享的 URL
  title: 'PJCHENder 那些沒告訴你的小細節', // 要分享的標題
  text: '好多眉眉角角啊', // 要分享的文字內容
};

btn.addEventListener('click', () => {
  // 判斷瀏覽器是否支援 Web Share API
  if (navigator.share) {
    handleNavigatorShare();
  } else {
    handleNotSupportNavigatorShare();
  }
});

// 當瀏覽器支援 Web Share API 時
async function handleNavigatorShare() {
  try {
    await navigator.share(shareData);
    result.textContent = '感謝你的的分享';
  } catch (err) {
    // 使用者拒絕分享或發生錯誤
    const { name } = err;
    if (name === 'AbortError') {
      result.textContent = '您已取消分享此訊息';
    } else {
      result.textContent = err;
      console.log('發生錯誤', err);
    }
  }
}

// 當瀏覽器不支援 Web Share API 時,點下去變成複製
function handleNotSupportNavigatorShare() {
  const contentToCopy = document.querySelector('#content-to-copy');
  contentToCopy.value = shareData.url;
  contentToCopy.setAttribute('type', 'text'); // 不是 hidden 才能複製
  contentToCopy.select();

  try {
    const successful = document.execCommand('copy');
    const msg = successful ? '成功' : '失敗';
    alert(`${shareData.url} - 複製${msg}`);
  } catch (err) {
    alert('Oops, unable to copy');
  }

  /* unselect the range */
  contentToCopy.setAttribute('type', 'hidden');
  window.getSelection().removeAllRanges();
}

參考文章

0 意見:

張貼留言