iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 12

Day 12 - 用 Fullscreen API、Clipboard API 打造沉浸展示與一鍵複製

  • 分享至 

  • xImage
  •  

昨天把「畫面/聲音 → 檔案」跑通(MediaDevices + MediaRecorder)。

今天要解鎖兩個在網頁上比較少主動用、很像手機原生功能的酷招:全螢幕展示、剪貼簿複製。這些 Web API 讓你的網頁「像 App 一樣能沉浸展示、能拷貝」,甚至直接跟手機體驗無縫接軌。來看看怎麼把這些日常神器搬到你的網頁上!🖥️ 🪞


一、Fullscreen API

重要 API 速覽

  • Element.requestFullscreen():讓元素進入全螢幕。
  • document.exitFullscreen():離開全螢幕。
  • document.fullscreenEnabled:是否支援全螢幕模式。
  • document.fullscreenElement:目前處於全螢幕的元素(或 null),可以用來判斷是否已在全螢幕。
  • 事件:fullscreenchangefullscreenerror
  • CSS::fullscreen::backdrop(可以調整全螢幕樣式與背景遮罩)。

為什麼要全螢幕?

讓內容更沉浸(投影片、影片播放、畫布工具、地圖、遊戲),排除瀏覽器 UI 干擾。

Fullscreen1
Fullscreen2

0) 全螢幕能力與政策偵測

// 功能是否可用
if (document.fullscreenEnabled === false) {
  console.warn('此環境不允許全螢幕(可能被 Permissions-Policy 或瀏覽器設定關閉)');
}

// 若在 <iframe> 中,外層需設定 allow
<iframe src="..." allow="fullscreen"></iframe>

1) DevTools 直接可貼的極簡範例(僅為示範,不建議正式使用)

這段刻意在瀏覽器 DevTools Console 直接呼叫 ,方便讀者立刻看到效果。
但請注意:requestFullscreen()使用者手勢觸發(如點擊、按鍵) 才最為穩定有效,因為瀏覽器為了避免惡意或自動全屏體驗,通常限制非使用者互動觸發的全螢幕請求會被擋掉。

// 建一個臨時元素
const div = document.createElement("div");
div.textContent = "Hello Fullscreen!";
div.style.cssText = `
  background: #00d2ff;
  color: white;
  font-size: 2rem;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 80vw;
  height: 80vh;
`;

document.body.appendChild(div);

// 瀏覽器 DevTools Console 直接執行,有時候會允許,但並非所有瀏覽器和情況都適用,存在不穩定現象甚至失敗。
div.requestFullscreen();

2) 完整可切換的示例(含 UI 同步與樣式)

<button id="toggle">Enter Fullscreen</button>
<div id="box">Hello Fullscreen!</div>

<style>
  #box {
    background: #00d2ff;
    color: white;
    font-size: 2rem;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 80vw;
    height: 80vh;
  }

  /* 在全螢幕狀態下改樣式(粉紅色) */
  #box:fullscreen { background: #ff4081; }
    
  /* 可選:改背板顏色 */
  :fullscreen::backdrop { background: rgba(0,0,0,.6); }
</style>

<script>
  const box = document.getElementById("box");
  const toggle = document.getElementById("toggle");

  // 1) 需使用者手勢觸發
  toggle.addEventListener("click", async () => {
    try {
      if (!document.fullscreenElement) {
        await box.requestFullscreen();
      } else {
        await document.exitFullscreen();
      }
    } catch (err) {
      console.error("Fullscreen error:", err);
      alert("無法切換全螢幕,請檢查瀏覽器權限或手勢觸發");
    }
  });

  // 2) 監聽狀態改變,動態更新 UI
  document.addEventListener("fullscreenchange", () => {
    toggle.textContent = document.fullscreenElement
      ? "Exit Fullscreen"
      : "Enter Fullscreen";
  });

  // 3) 可選:錯誤事件
  document.addEventListener("fullscreenerror", () => {
    console.warn("Fullscreen error event fired");
  });
</script>

注意事項

  • 需要使用者手勢觸發(如點擊、按鍵) 觸發 requestFullscreen()
  • document.fullscreenElement 判斷是否已在全螢幕;搭配 fullscreenchange 監聽狀態改變維護 UI。
  • CSS :fullscreen::backdrop 可在全螢幕時套不同樣式,調整全螢幕樣式與背景遮罩。
  • 內嵌於 <iframe> 時,外層需 allow="fullscreen"allowfullscreen
  • ESC / 系統手勢 可退出。

二、Clipboard API(複製/貼上)

重要 API 速覽

  • navigator.clipboard.writeText(text) / write(items):寫入剪貼簿(Copy/Cut)。
  • navigator.clipboard.readText() / read():讀取剪貼簿(Paste/Read)。
  • ClipboardItem:支援圖片/檔案的剪貼簿項目。
  • DOM 事件:copycutpaste
  • 備援(舊式):document.execCommand('copy')(相容性最後防線)。

Clipboard

1) 程式化複製文字

<input id="copyInput" value="Hello Clipboard!" />
<button id="btnCopy">Copy</button>

<script>
  const btn = document.getElementById('btnCopy');
  const input = document.getElementById('copyInput');

  btn.addEventListener('click', async () => {
    const t = input.value;
    try {
      await navigator.clipboard.writeText(t);
      console.log('copied');
    } catch {
      // 最小備援:建立隱形 <textarea> + execCommand('copy')
      // 建一個 <textarea>,把要複製的字串 t 放進去
      const ta = Object.assign(document.createElement('textarea'), { value: t });
      
      // 放進 DOM、不可見且不影響版面
      ta.style.position='fixed';
      ta.style.opacity='0';
      document.body.appendChild(ta);
      
      // 程式選取 textarea 內容,準備進行複製
      ta.select();
      
      // 呼叫舊式 API 把選取到的文字放入剪貼簿
      document.execCommand('copy');
      
      ta.remove();
    }
  });
</script>

建議把 writeText('內容') 綁在按鈕 click 事件中,符合「使用者手勢」,取得權限,容易複製成功。

2) 讀取文字

A. 程式主動讀剪貼簿(可能會要求權限):readText()

  • 「程式主動讀剪貼簿」,瀏覽器會以更嚴格的隱私模型處理,通常需 HTTPS使用者啟動(user activation),而且可能跳出權限提示,使用者一旦拒絕就會失敗。
  • 企業政策、擴充套件、防毒軟體常會攔截「程式化讀取」。
<button id="btnRead">Read from clipboard</button>
<pre id="out"></pre>

<script>
    const out = document.getElementById('out');
    
    document.getElementById('btnRead').addEventListener('click', async () => {
    try {
      const text = await navigator.clipboard.readText(); // 需 HTTPS + 手勢;可能彈權限
      out.textContent = text || '(剪貼簿目前是空的)';
    } catch {
      out.textContent = '無法讀取(需要權限/HTTPS,或瀏覽器不支援)';
    }
  });
</script>

B. 使用者主動貼上(最穩定):paste 事件

  • 「使用者主動貼上」,這已是明確的使用者意圖,瀏覽器會在事件對象上提供 clipboardData通常不需要再跳權限,因此成功率更高、行為更可預期。
  • 事件導向、一次性的使用者動作,風險較低,因此較少被政策阻擋,但仍須確保輸入元素已聚焦、網站未禁用貼上。
<input id="pasteHere" placeholder="在這裡按 ⌘V / Ctrl+V" />

<script>
    // paste 事件
    document.getElementById('pasteHere').addEventListener('paste', (e) => {
    const t = e.clipboardData?.getData('text') ?? '';
    console.log('PASTE:', t);
  });
</script>

讀取(paste/read)屬於隱私敏感 → 多半需要 HTTPS + 手勢 + 可能的權限詢問。若被拒絕,請提供替代流程(例如提示使用者在輸入框按 ⌘V/Ctrl+V)。

3) 複製圖片(Canvas → PNG)

若不支援圖片複製,可改用「下載檔案」或 Web Share API 分享檔案。

<canvas id="cv" width="160" height="90"></canvas>
<button id="btnCopyImg">Copy Canvas PNG</button>

<script>
  const cv = document.getElementById('cv');
  const ctx = cv.getContext('2d');
  ctx.fillStyle = '#09f';
  ctx.fillRect(0,0,160,90); // 畫點東西

  document.getElementById('btnCopyImg').addEventListener('click', () => {
    cv.toBlob(async (b) => {
      if (!('ClipboardItem' in window)) return alert('此瀏覽器暫不支援圖片複製');
      try {
        await navigator.clipboard.write([new ClipboardItem({ 'image/png': b })]);
        console.log('image copied');
      } catch {
        alert('複製圖片失敗(可能需要權限或 HTTPS)');
      }
    }, 'image/png');
  });
</script>

注意事項

  • HTTPS / localhost 幾乎是必備,否則現代剪貼簿 API 會失敗。
  • 使用者手勢(click/tap)能大幅提高成功率;請避免在頁面載入時自動讀寫。
  • 讀取(paste/read)更敏感:可能彈出權限,或在未獲授權時被拒(尤其桌機瀏覽器)。
  • 寫入(copy/write)相對寬鬆:通常只要手勢即可。
  • document.execCommand('copy') 是舊式 API
    • 仍被廣泛支援,但屬於相容性備援;未來可能逐步淡出。
    • 限制多、行為依瀏覽器而異,請把它當最後防線(例如 HTTP 環境)。

範例 Demo

上面用簡單程式碼示範了「全螢幕展示、剪貼簿複製」的基本流程。
想直接體驗完整互動,請看這個線上範例(本文截圖也來自這裡):


👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 11 - 錄製螢幕畫面與聲音!MediaDevices + MediaRecorder
系列文
從 Canvas 到各式各樣的 Web API 之旅12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言