Как обращаться с файлами, открытыми из проводника

Паланс Ляо
Palances Liao

Сначала объявите атрибут file_handlers в манифесте вашего веб-приложения. API обработки файлов требует, чтобы вы указали свойство action (URL-адрес обработки) и свойство accept , которое представляет собой объект с типами MIME в качестве ключей и массивов соответствующих расширений файлов.

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

Далее вам нужно использовать API обработки файлов, чтобы принудительно обрабатывать открытые файлы через 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.
   
}
 
});
}

Поддержка браузера

  • 102
  • 102
  • Икс
  • Икс

Источник

Классический способ

Использование классического метода DataTransferItem.getAsFile()

Если API обработки файлов не поддерживается, вы все равно можете перетаскивать файлы из проводника в приложение. Метод DataTransferItem.getAsFile() возвращает объект File элемента данных перетаскивания. Если элемент не является файлом, этот метод возвращает значение null . Хотя вы можете прочитать файл, нет возможности выполнить обратную запись. Этот метод имеет тот недостаток, что он не поддерживает каталоги.

Поддержка браузера

  • 11
  • 12
  • 50
  • 5.1

Источник

Прогрессивное улучшение

В приведенном ниже фрагменте используется API обработки файлов, если он доступен, а также дополнительно регистрируются обработчики перетаскивания, чтобы можно было обрабатывать перетаскиваемые файлы.

Объявите типы файлов, которые можно обрабатывать, в манифесте веб-приложения. Браузеры, которые не поддерживают API обработки файлов, просто проигнорируют это.

{
 
"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.
   
}
 
}
});

дальнейшее чтение

Демо

<!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>

        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;
}
       

       
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}

`;
   
}
 
});
}