كيفية التعامل مع الملفات المفتوحة من مستكشف الملفات

Palances Liao
Palances Liao

الطريقة الحديثة

استخدام File Handling API

أولاً، عليك الإعلان عن السمة file_handlers في بيان تطبيق الويب. تتطلّب منك File Handling API تحديد السمة action (عنوان URL للمعالجة) والسمة accept، وهي عنصر يحتوي على أنواع MIME كمفاتيح ومصفوفات من امتدادات الملفات المقابلة بشكل خاص.

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

بعد ذلك، عليك استخدام File Handling 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.
    }
  });
}

Browser Support

  • Chrome: 102.
  • Edge: 102.
  • Firefox: not supported.
  • Safari: not supported.

Source

الطريقة الكلاسيكية

استخدام الطريقة الكلاسيكية DataTransferItem.getAsFile()

إذا لم تكن File Handling API متاحة، سيظل بإمكانك سحب الملفات وإفلاتها من مستكشف الملفات إلى التطبيق. تعرض الطريقة DataTransferItem.getAsFile() عنصر File لبيانات السحب والإفلات. إذا لم يكن العنصر ملفًا، تعرض هذه الطريقة null. يمكنك قراءة الملف، ولكن لا يمكنك الكتابة فيه. تتمثّل عيوب هذه الطريقة في أنّها لا تتيح استخدام الدليل.

Browser Support

  • Chrome: 11.
  • Edge: 12.
  • Firefox: 50.
  • Safari: 5.1.

Source

التحسين التدريجي

تستخدم المقتطفات أدناه File Handling API عندما تكون متاحة، وتسجِّل بالإضافة إلى ذلك معالِجات السحب والإفلات حتى يمكن معالجة الملفات التي تم سحبها.

عليك الإعلان عن أنواع الملفات التي يمكن معالجتها في بيان تطبيق الويب. ستتجاهل المتصفّحات التي لا تتيح File Handling 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.
    }
  }
});

محتوى إضافي للقراءة

عرض توضيحي

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}

`; } }); }