نحوه کشیدن و رها کردن فایل ها

رابط‌های کشیدن و رها کردن HTML، برنامه‌های کاربردی وب را قادر می‌سازد تا فایل‌های کشیده و رها شده را در یک صفحه وب بپذیرند. در طول عملیات کشیدن و رها کردن، آیتم های فایل و دایرکتوری کشیده شده به ترتیب با ورودی های فایل و ورودی های دایرکتوری مرتبط می شوند. وقتی صحبت از کشیدن و رها کردن فایل ها به مرورگر می شود، دو راه برای انجام آن وجود دارد: روش مدرن و کلاسیک.

روش مدرن

با استفاده از روش File System Access API DataTransferItem.getAsFileSystemHandle()

متد DataTransferItem.getAsFileSystemHandle() یک وعده را با یک شی FileSystemFileHandle برمی گرداند اگر آیتم کشیده شده یک فایل باشد، و یک وعده با یک شی FileSystemDirectoryHandle اگر مورد کشیده شده یک دایرکتوری باشد. این دسته‌ها به شما امکان می‌دهند که بخوانید و به صورت اختیاری دوباره به فایل یا دایرکتوری بنویسید. توجه داشته باشید که DataTransferItem.kind واسط Drag and Drop برای فایل ها و دایرکتوری ها "file" خواهد بود، در حالی که FileSystemHandle.kind API File System Access برای فایل ها "file" و برای دایرکتوری ها "directory" خواهد بود.

پشتیبانی مرورگر

  • 86
  • 86
  • ایکس
  • ایکس

منبع

روش کلاسیک

با استفاده از متد کلاسیک DataTransferItem.getAsFile()

متد DataTransferItem.getAsFile() شی File مورد داده را برمی گرداند. اگر مورد یک فایل نباشد، این روش null را برمی‌گرداند. در حالی که می توانید فایل را بخوانید، هیچ راهی برای نوشتن مجدد به آن وجود ندارد. این روش دارای این عیب است که از دایرکتوری ها پشتیبانی نمی کند.

پشتیبانی مرورگر

  • 11
  • 12
  • 50
  • 5.1

منبع

افزایش پیشرونده

قطعه زیر از روش مدرن File System Access API DataTransferItem.getAsFileSystemHandle() استفاده می کند، سپس به روش غیر استاندارد DataTransferItem.webkitGetAsEntry() باز می گردد و در نهایت به متد کلاسیک DataTransferItem.getAsFile() باز می گردد. حتما نوع هر handle را بررسی کنید، زیرا ممکن است یکی از موارد زیر باشد:

  • FileSystemFileHandle زمانی که مسیر کد مدرن انتخاب می شود.
  • زمانی که مسیر کد کلاسیک انتخاب شد، File کنید.

همه انواع دارای یک ویژگی name هستند، بنابراین ثبت آن خوب است و همیشه کار خواهد کرد.

// Run feature detection.
const supportsFileSystemAccessAPI =
  'getAsFileSystemHandle' in DataTransferItem.prototype;

// 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) =>
      supportsFileSystemAccessAPI
        // …either get a modern `FileSystemHandle`…
        ? item.getAsFileSystemHandle()
        // …or a classic `File`.
        : 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.kind === 'file' || handle.isFile) {
      console.log(`File: ${handle.name}`);
    }
  }
});

بیشتر خواندن

نسخه ی نمایشی

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>How to drag and drop files</title>
  </head>
  <body>
    <main>
      <h1>How to drag and drop files</h1>
      <p>Drag and drop one or multiple files onto the page.</p>
      <pre></pre>
    </main>
  </body>
</html>

CSS


        :root {
  color-scheme: dark light;
  box-sizing: border-box;
}

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

body {
  margin: 0;
  padding: 1rem;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

img,
video {
  height: auto;
  max-width: 100%;
}

main {
  flex-grow: 1;
}

footer {
  margin-top: 1rem;
  border-top: solid CanvasText 1px;
  font-size: 0.8rem;
}
        

JS


        const supportsFileSystemAccessAPI =
  "getAsFileSystemHandle" in DataTransferItem.prototype;
const supportsWebkitGetAsEntry =
  "webkitGetAsEntry" in DataTransferItem.prototype;

const elem = document.querySelector("main");
const debug = document.querySelector("pre");

elem.addEventListener("dragover", (e) => {
  // Prevent navigation.
  e.preventDefault();
});

elem.addEventListener("dragenter", (e) => {
  elem.style.outline = "solid red 1px";
});

elem.addEventListener("dragleave", (e) => {
  elem.style.outline = "";
});

elem.addEventListener("drop", async (e) => {
  e.preventDefault();
  elem.style.outline = "";
  const fileHandlesPromises = [...e.dataTransfer.items]
    .filter((item) => item.kind === "file")
    .map((item) =>
      supportsFileSystemAccessAPI
        ? item.getAsFileSystemHandle()
        : supportsWebkitGetAsEntry
        ? item.webkitGetAsEntry()
        : item.getAsFile()
    );

  for await (const handle of fileHandlesPromises) {
    if (handle.kind === "directory" || handle.isDirectory) {
      console.log(`Directory: ${handle.name}`);
      debug.textContent += `Directory: ${handle.name}\n`;
    } else {
      console.log(`File: ${handle.name}`);
      debug.textContent += `File: ${handle.name}\n`;
    }
  }
});