使用檔案
您的瀏覽器擴充套件程式可能需要使用檔案才能實現全部功能。本文將介紹處理檔案的五種機制。
- 將檔案下載到使用者選定的下載資料夾。
- 使用網頁上的檔案選擇器開啟檔案。
- 使用拖放方式將檔案拖放到網頁上開啟。
- 使用 idb-file-storage 庫將檔案或 blob 本地儲存到 IndexedDB 中。
- 將檔案傳遞給使用者計算機上的原生應用程式。
對於每種機制,我們都將介紹其用法,並引用相關的 API 文件、指南和使用 API 的示例。
使用 Downloads API 下載檔案
此機制使您能夠將檔案從您的網站(或任何您定義為 URL 的位置)傳輸到使用者計算機。關鍵方法是 downloads.download(),它最簡單的形式接受一個 URL,並將該 URL 的檔案下載到使用者的預設下載資料夾。
browser.downloads.download({ url: "https://example.org/image.png" });
您可以透過指定 saveAs 引數,讓使用者下載到他們選擇的位置。
注意:使用 URL.createObjectURL(),您還可以下載 JavaScript 中定義的檔案和 blob,包括從 IndexedDB 檢索到的本地內容。
Downloads API 還提供了取消、暫停、恢復、擦除和刪除下載的功能;在下載管理器中搜索已下載檔案;在計算機的檔案管理器中顯示已下載檔案;以及在關聯的應用程式中開啟檔案。
要使用此 API,您需要在 manifest.json 檔案中指定 "downloads" API 許可權。
示例:Latest download API 參考:downloads API
使用檔案選擇器在擴充套件程式中開啟檔案
如果您想處理使用者計算機上的檔案,一種選擇是讓使用者使用計算機的檔案瀏覽器選擇檔案。您可以建立一個新頁面,或者將程式碼注入現有頁面,以使用 HTML input 元素的 file 型別為使用者提供檔案選擇器。使用者選擇檔案後,與頁面關聯的指令碼就可以像 Web 應用程式一樣使用 DOM File API 訪問檔案內容。
示例:Imagify 指南:使用 Web 應用程式中的檔案 API 參考:HTML input 元素 | DOM File API
注意:如果您想訪問或處理所選資料夾中的所有檔案,可以使用 <input type="file" webkitdirectory="true"/> 來選擇資料夾並返回其中包含的所有檔案。
使用拖放方式在擴充套件程式中開啟檔案
Web Drag and Drop API 提供了一種替代檔案選擇器的方法。要使用此方法,請建立一個符合您 UI 的“放置區”,然後在該元素上新增 dragenter、dragover 和 drop 事件的偵聽器。在 drop 事件的處理程式中,您的程式碼可以使用 DataTransfer.files 屬性提供的物件訪問使用者拖放的任何檔案。然後,您的程式碼可以使用 DOM File API 訪問和操作這些檔案。
示例:Imagify 指南:使用 Web 應用程式中的檔案 | 檔案拖放 API 參考:DOM File API
使用 IndexedDB 檔案儲存庫本地儲存檔案資料
如果您的擴充套件程式需要在本地儲存檔案,idb-file-storage 庫 提供了一個簡單的基於 Promise 的 IndexedDB API 封裝,用於方便地儲存和檢索檔案和 blobs。
該庫的關鍵功能包括:
- getFileStorage
-
返回一個
IDBFileStorage例項,如果命名的儲存不存在,則建立它。 - IDBFileStorage
-
提供儲存和檢索檔案的各種方法,例如:
- list 用於獲取資料庫中檔案的可選過濾列表。
- put 用於將檔案或 blob 新增到資料庫。
- get 用於從資料庫檢索檔案或 blob。
- remove 用於從資料庫刪除檔案或 blob。
Store Collected Images 示例演示瞭如何使用這些功能的大部分。
Store Collected Images 示例允許使用者透過影像上下文選單中的一個選項將影像新增到集合中。選定的影像會收集在彈出視窗中,並可以儲存到命名的集合中。一個工具欄按鈕(browserAction)會開啟一個導航集合頁面,使用者可以在其中檢視和刪除已儲存的影像,並提供篩選選項來縮小選擇範圍。 觀看示例的實際演示。
可以透過檢視 /utils/ 中的 image-store.js 來理解該庫的工作原理。
建立儲存並儲存影像
async function saveCollectedBlobs(collectionName, collectedBlobs) {
const storedImages = await getFileStorage({ name: "stored-images" });
for (const item of collectedBlobs) {
await storedImages.put(`${collectionName}/${item.uuid}`, item.blob);
}
}
當用戶在彈出視窗中點選“儲存”並提供了影像集合的名稱後,會呼叫 saveCollectedBlobs。
首先,getFileStorage 會建立(如果尚不存在)或檢索 IndexedDB 資料庫 "stored-images" 並將其賦給 storedImages 物件。然後,storedImages.put() 會將每個收集到的影像新增到資料庫中,放在集合名稱下,使用 blob 的唯一 ID(檔名)。
如果正在儲存的影像的名稱與資料庫中已有的影像名稱相同,它將被覆蓋。如果您想避免這種情況,請先使用帶有檔名過濾器的 imagesStore.list() 查詢資料庫;如果列表返回了一個檔案,則為新影像的名稱新增一個合適的字尾,以儲存一個單獨的項。
檢索已儲存的影像以供顯示
export async function loadStoredImages(filter) {
const imagesStore = await getFileStorage({ name: "stored-images" });
let listOptions = filter ? { includes: filter } : undefined;
const imagesList = await imagesStore.list(listOptions);
let storedImages = [];
for (const storedName of imagesList) {
const blob = await imagesStore.get(storedName);
storedImages.push({ storedName, blobUrl: URL.createObjectURL(blob) });
}
return storedImages;
}
當用戶在導航集合頁面中點選“檢視”或“重新載入”時,會呼叫 loadStoredImages()。getFileStorage() 會開啟 "stored-images" 資料庫,然後 imagesStore.list() 會獲取已儲存影像的過濾列表。然後使用此列表透過 imagesStore.get() 檢索影像,並構建一個列表返回給 UI。
請注意,使用 URL.createObjectURL(blob) 來建立一個引用影像 blob 的 URL。然後,此 URL 會在 UI(navigate-collection.js)中使用以顯示影像。
刪除收集的影像
async function removeStoredImages(storedImages) {
const imagesStore = await getFileStorage({ name: "stored-images" });
for (const storedImage of storedImages) {
URL.revokeObjectURL(storedImage.blobUrl);
await imagesStore.remove(storedImage.storedName);
}
}
當用戶在導航集合頁面中點選“刪除”時,會呼叫 removeStoredImages()。同樣,getFileStorage() 會開啟 "stored-images" 資料庫,然後 imagesStore.remove() 會從已過濾的影像列表中刪除每個影像。
請注意,使用 URL.revokeObjectURL() 來顯式撤銷 blob URL。這使得垃圾回收器能夠釋放為 URL 分配的記憶體。如果不這樣做,記憶體直到建立該 URL 的頁面關閉後才會被釋放。如果在擴充套件程式的後臺頁面中建立了 URL,則該 URL 直到擴充套件程式被停用、解除安裝或重新載入後才會被解除安裝,因此不必要地佔用此記憶體可能會影響瀏覽器效能。如果在擴充套件程式的頁面(新標籤頁、彈出視窗或側邊欄)中建立了 URL,則在關閉頁面時記憶體會被釋放,但仍建議在不再需要 URL 時撤銷它。
一旦 blob URL 被撤銷,任何嘗試載入它的行為都會導致錯誤。例如,如果 blob URL 被用作 IMG 標籤的 SRC 屬性,影像將不會載入並且不可見。因此,在撤銷 blob URL 時,最好將其從生成的 HTML 元素中移除。
示例:Store Collected Images API 參考:idb-file-storage 庫
注意:您也可以使用完整的 Web IndexedDB API 來儲存擴充套件程式的資料。這在您需要儲存 DOM Storage API 提供的簡單鍵/值對無法很好處理的資料時可能很有用。
在本地應用程式中處理檔案
當您擁有一個原生應用程式或想要為檔案處理提供額外的原生功能時,可以使用原生訊息傳遞將檔案傳遞給原生應用程式進行處理。
您有兩種選擇:
- 基於連線的訊息傳遞
-
在這裡,您透過
runtime.connectNative()觸發該過程,它返回一個runtime.Port物件。然後,您可以使用Port的postMessage()函式將 JSON 訊息傳遞給原生應用程式。使用Port的onMessage.addListener()函式,您可以偵聽來自原生應用程式的訊息。當呼叫runtime.connectNative()時,如果原生應用程式未執行,則會開啟它,並且該應用程式將保持執行狀態,直到擴充套件程式呼叫Port.disconnect()或連線到它的頁面關閉。 - 無連線訊息傳遞
-
在這裡,您使用
runtime.sendNativeMessage()將 JSON 訊息傳送到原生應用程式的一個新、臨時的例項。瀏覽器會在收到原生應用程式的任何訊息後關閉原生應用程式。
要新增原生應用程式要處理的檔案或 blob,請使用 JSON.stringify()。
要使用此方法,擴充套件程式必須在其 manifest.json 檔案中請求 "nativeMessaging" 許可權或可選許可權。如果使用可選許可權,請記住檢查該許可權是否已被授予,並在必要時使用 permissions API 向用戶請求許可權。反之,原生應用程式必須在其應用程式清單的 "allowed_extensions" 欄位中包含其 ID,以授予擴充套件程式許可權。
示例:Native Messaging(僅演示簡單訊息傳遞)指南:Native messaging API 參考:runtime API