Cách xử lý các tệp được mở qua trình khám phá tệp

Palances Liao
Palances Liao

Phong cách hiện đại

Sử dụng API xử lý tệp

Trước tiên, hãy khai báo thuộc tính file_handlers trong tệp kê khai ứng dụng web. API Xử lý tệp yêu cầu bạn chỉ định thuộc tính action (URL xử lý) và thuộc tính accept. Đây là một đối tượng có loại MIME dưới dạng khoá và mảng của đuôi tệp cụ thể tương ứng.

{
  "file_handlers": [
    {
      "action": "./",
      "accept": {
        "image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
      }
    }
  ]
}

Tiếp theo, bạn cần sử dụng API Xử lý tệp để xử lý bắt buộc các tệp đã mở thông qua launchQueue.

if ('launchQueue' in window && 'files' in LaunchParams.prototype) {
  launchQueue.setConsumer((launchParams) => {
    if (!launchParams.files.length) {
      return;
    }
    for (const fileHandle of launchParams.files) {
      // Handle the file.
    }
  });
}

Hỗ trợ trình duyệt

  • 102
  • 102
  • lần
  • lần

Cách cổ điển

Sử dụng phương thức DataTransferItem.getAsFile() cổ điển

Nếu API Xử lý tệp không được hỗ trợ, bạn vẫn có thể kéo và thả tệp từ trình khám phá tệp vào ứng dụng. Phương thức DataTransferItem.getAsFile() trả về đối tượng File của mục dữ liệu kéo. Nếu mục không phải là tệp, phương thức này sẽ trả về null. Mặc dù bạn có thể đọc tệp, nhưng không có cách nào để ghi lại vào tệp đó. Phương thức này có nhược điểm là không hỗ trợ các thư mục.

Hỗ trợ trình duyệt

  • 11
  • 12
  • 50
  • 5.1

Nguồn

Nâng cao dần dần

Đoạn mã dưới đây sử dụng API xử lý tệp khi có sẵn, đồng thời đăng ký thêm các trình xử lý kéo và thả để có thể xử lý các tệp đã kéo.

Khai báo các loại tệp có thể xử lý trong tệp kê khai ứng dụng web. Những trình duyệt không hỗ trợ API xử lý tệp sẽ bỏ qua thông báo này.

{
  "file_handlers": [
    {
      "action": "./",
      "accept": {
        "image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
      }
    }
  ]
}
// File Handling API
const handleLaunchFiles = () => {
  window.launchQueue.setConsumer((launchParams) => {
    if (!launchParams.files.length) {
      return;
    }
    launchParams.files.forEach(async (handle) => {
      const file = await handle.getFile();
      console.log(`File: ${file.name}`);
      // Do something with the file.
    });
  });
};

if ('launchQueue' in window && 'files' in LaunchParams.prototype) {
  handleLaunchFiles();
}

// This is the drag and drop zone.
const elem = document.querySelector('main');
// Prevent navigation.
elem.addEventListener('dragover', (e) => {
  e.preventDefault();
});
// Visually highlight the drop zone.
elem.addEventListener('dragenter', (e) => {
  elem.style.outline = 'solid red 1px';
});
// Visually unhighlight the drop zone.
elem.addEventListener('dragleave', (e) => {
  elem.style.outline = '';
});
// This is where the drop is handled.
elem.addEventListener('drop', async (e) => {
  // Prevent navigation.
  e.preventDefault();
  // Unhighlight the drop zone.
  elem.style.outline = '';
  // Prepare an array of promises…
  const fileHandlesPromises = [...e.dataTransfer.items]
    // …by including only files (where file misleadingly means actual file _or_
    // directory)…
    .filter((item) => item.kind === 'file')
    // …and, depending on previous feature detection…
    .map((item) => item.getAsFile());
  // Loop over the array of promises.
  for await (const handle of fileHandlesPromises) {
    // This is where we can actually exclusively act on the files.
    if (handle.isFile) {
      console.log(`File: ${handle.name}`);
      // Do something with the file.
    }
  }
});

Tài liệu đọc thêm

Bản minh họa

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="manifest" href="manifest.json" />
    <title>How to handle files opened from the file explorer</title>
    <link rel="stylesheet" href="style.css" />
    <!-- TODO: Devsite - Removed inline handlers -->
    <!-- <script>
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', async () => {
          const registration = await navigator.serviceWorker.register(
            'sw.js',
          );
          console.log(
            'Service worker registered for scope',
            registration.scope,
          );
        });
      }
    </script>
    <script src="script.js" type="module"></script> -->
  </head>
  <body>
    <h1>How to handle files opened from the file explorer</h1>
    <p>Install the app. After the installation, try opening an image file from the file explorer with the app.
  </body>
</html>

CSS


        html {
  box-sizing: border-box;
  font-family: system-ui, sans-serif;
  color-scheme: dark light;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
}

img {
  height: auto;
  max-width: 100%;
  display: block;
}
        

JS


        if ('launchQueue' in window && 'files' in LaunchParams.prototype) {
  launchQueue.setConsumer((launchParams) => {
    if (!launchParams.files.length) {
      return;
    }
    for (const fileHandle of launchParams.files) {
      document.body.innerHTML += `

${fileHandle.name}

`; } }); }