Published on

Electron 中的文件拖拽

Authors

从桌面或文件夹中拖拽文件到 Electron 应用中,以及在 Electron 应用中拖拽文件到桌面或文件夹中,核心是 dragstartdragoverdrop 等 DOM 事件,以及 webContents.startDrag(item) 这个 Electron 提供的 API。

从桌面或文件夹拖拽文件到 Electron 应用

  1. 定义可接受区域以及其样式
<div
  id="drop_zone"
  ondrop="dropHandler(event);"
  ondragover="dragOverHandler(event);">
  <p>Drag one or more files to this <i>drop zone</i>.</p>
</div>
#drop_zone {
  border: 5px solid blue;
  width: 200px;
  height: 100px;
}
  1. 处理事件

为了能触发 drop 事件,我们需要 在 dragover 事件处理中 ev.preventDefault();

function dragOverHandler(ev) {
  console.log("File(s) in drop zone");

  // Prevent default behavior (Prevent file from being opened)
  ev.preventDefault();
}

使用 dataTransfer 属性来获取文件信息,注意 itemsfiles 都是类数组的,既不能使用数组的方法来遍历

function dropHandler(ev) {
  console.log("File(s) dropped");

  // Prevent default behavior (Prevent file from being opened)
  ev.preventDefault();

  if (ev.dataTransfer.items) {
    // Use DataTransferItemList interface to access the file(s)
    [...ev.dataTransfer.items].forEach((item, i) => {
      // If dropped items aren't files, reject them
      if (item.kind === "file") {
        const file = item.getAsFile();
        console.log(`… file[${i}].name = ${file.name}`);
      }
    });
  } else {
    // Use DataTransfer interface to access the file(s)
    [...ev.dataTransfer.files].forEach((file, i) => {
      console.log(`… file[${i}].name = ${file.name}`);
    });
  }
}
  1. 优化体验

可以让接收拖拽文件的区域样式变化来提升用户体验,可以借助 dragenterdragleave 这两个事件

可以高亮背景或者边框来提示可以接收文件拖拽

function dragEnterHandler(ev) {
  ev.preventDefault();
  ev.stopPropagation();
  
  // modify the css of drag-zone
}

重置样式

function dragLeaveHandler(ev) {
  ev.preventDefault();
  ev.stopPropagation();
  
  // reset the css of drag-zone
}

从 Electron 应用拖拽文件到桌面或文件夹

  1. 定义可拖拽区域以及其样式
<div draggable="true" id="drag-zone">Drag me</div>
#drag-zone {
  border:2px solid black;
  border-radius:3px;
  padding:5px;
  display:inline-block;
}
  1. 处理事件

我们需要借助 dragstart 这个事件,通过 IPC 调用 contents.startDrag(item)

renderer.js 文件定义如下:

document.getElementById('drag-zone').ondragstart = (event) => {
  event.preventDefault();
  window.electron.startDrag('drag-and-drop-1.md');
}

preload.js 文件如下定义:

const { contextBridge, ipcRenderer } = require('electron/renderer')

contextBridge.exposeInMainWorld('electron', {
  startDrag: (fileName) => ipcRenderer.send('ondragstart', fileName)
})

main.js 文件定义如下:

ipcMain.on('ondragstart', (event, filePath) => {
  event.sender.startDrag({
    file: path.join(__dirname, filePath),
    icon: iconName
  })
})
  1. 注意事项
  • 需要被拖拽的文件必须要在硬盘存在,不能是网络文件

发现的问题

  1. console.log(e) 没有结果,但是 e.dataTransfer.files 有值

参考链接:

https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop

https://www.electronjs.org/docs/latest/api/web-contents#contentsstartdragitem

https://www.electronjs.org/docs/latest/tutorial/native-file-drag-drop