純前端也可以訪問文件系統!

前言

週末逛github的時候,發現我們只需要在github域名上加上1s他就能夠打開一個vscode窗口來閱讀代碼,比起在github倉庫中查看更加方便

然後我就想網頁端vscode能不能打開我本地的項目呢,帶着這個疑惑我打開了網頁版vscode,它居然真的可以打開我本地的項目代碼!

難道又出了新的API讓前端的能力更進一步了?打開MDN查了一下相關文檔,發現了幾個新的API

showOpenFilePicker

用來選擇文件

語法

showOpenFilePicker()

參數

  • options:(可選)包含以下屬性
    • multiple:布爾值,默認爲false。爲true表示允許用戶選擇多個文件
    • excludeAcceptAllOption:布爾值,默認爲false。默認情況下,文件選擇器帶有一個允許用戶選擇所有類型文件的過濾選項(展開於文件類型選項中)。設置此選項爲 true 以使該過濾選項不可用。
    • types:表示允許選擇的文件類型的數組

返回值

返回一個promise對象,會兌現一個包含 FileSystemFileHandle 對象的 Array 數組。

體驗

<template>
  <div class="open_file" @click="openFile">打開文件</div>
</template>

<script setup lang="ts">
const openFile = async () => {
  const res = await window.showOpenFilePicker();
  console.log(res);
};
</script>

默認只能打開一個文件,可以傳入multiple:true打開多個文件

showDirectoryPicker

用來選擇目錄

語法

屬於瀏覽器全局方法,直接調用即可

showDirectoryPicker()

參數

  • options:(可選)包含以下屬性
    • multiple:布爾值,默認爲false。爲true表示允許用戶選擇多個文件
    • excludeAcceptAllOption:布爾值,默認爲false。默認情況下,文件選擇器帶有一個允許用戶選擇所有類型文件的過濾選項(展開於文件類型選項中)。設置此選項爲 true 以使該過濾選項不可用。
    • types:表示允許選擇的文件類型的數組

返回值

返回一個promise對象,會兌現一個包含 FileSystemFileHandle 對象的 Array 數組。

體驗

<template>
  <div class="open_file" @click="openFile">打開文件</div>
  <div class="open_file" @click="openDir">打開文件夾</div>
</template>

<script setup lang="ts">
const openFile = async () => {
  const res = await window.showOpenFilePicker({
    // multiple: true,
  });
  console.log(res.length);
};

const openDir = async () => {
  const res = await window.showDirectoryPicker();
  console.log(res);
};
</script>

擴展

FileSystemFileHandle

FileSystemFileHandle提供了一些方法可以用來獲取和操作文件

  • getFile:返回一個Promise對象,用於獲取文件;

  • createSyncAccessHandle:返回一個FileSystemSyncAccessHandle對象,用於同步訪問文件;

  • createWritable:返回一個Promise對象,用於創建一個可寫流,用於寫入文件;

FileSystemDirectoryHandle

FileSystemDirectoryHandle對象是一個代表文件系統中的目錄的對象,它同樣提供了方法來獲取和操作目錄

  • entries:返回一個AsyncIterable對象,用於獲取目錄中的所有文件和目錄;
  • keys:返回一個AsyncIterable對象,用於獲取目錄中的所有文件和目錄的名稱;
  • values:返回一個AsyncIterable對象,用於獲取目錄中的所有文件和目錄的FileSystemHandle對象;
  • getFileHandle:返回一個Promise對象,用於獲取目錄中的文件;
  • getDirectoryHandle:返回一個Promise對象,用於獲取目錄中的目錄;
  • removeEntry:返回一個Promise對象,用於刪除目錄中的文件或目錄;
  • resolve:返回一個Promise對象,用於獲取目錄中的文件或目錄;

entrieskeysvalues這三個方法都是用來獲取目錄中的所有文件和目錄的,它們返回的都是一個AsyncIterable對象,我們可以通過for await...of語法來遍歷它。

開發編輯器

瞭解完這些知識點,我們就可以來開發一個簡陋網頁版編輯器了,初期只包含打開文件、打開文件夾、查看文件、切換文件

編輯器大概長這樣:

打開文件夾

const openDir = async () => {
  const res = await window.showDirectoryPicker({});
  const detalAction = async (obj: any) => {
    if (obj.entries) {
      const dirs = obj.entries();
      for await (const entry of dirs) {
        if (entry[1].entries) {
          // 文件夾,遞歸處理
          detalAction(entry[1]);
        } else {
          // 文件
          fileList.value.push({
            name: entry[0],
            path: obj.name,
            fileHandle: entry[1],
          });
        }
      }
    }
  };
  await detalAction(res);
  showCode(fileList.value[0], 0);
  console.log("--fileList--", fileList);
};

這裏主要是遞歸處理文件夾,返回一個文件列表

讀取文件內容

const showCode = async (item: any, index: number) => {
  const file = await item.fileHandle.getFile();
  const text = await file.text();
  codeText.value = text;
  currentIndex.value = index;
};

展示文件內容

使用highlight.js來高亮展示代碼

<div class="show_code">
  <pre v-highlight>
        <code class="lang-dart">
            {{ codeText }}
        </code>
   </pre>
</div>

最終效果如下:

想不到吧,這種功能現在純前端就能夠實現了,當然還可以做的更復雜一點,包括修改保存等功能,保存可以使用showSaveFilePickerAPI,它可以寫入文件,同樣是返回一個promise。感興趣的可以試着完善編輯器的功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章