前言
最近碰到一个小需求,简单记录一下:我想在 Tauri 里实现 将文件拖拽到指定区域,并直接获取其绝对路径。一开始下意识地用了 Web 的常规做法,结果发现事情没那么简单。
Web 实现方案
首先,确保在 tauri.conf.json
中将窗口的 dragDropEnabled
设置为 false
,防止系统层级的拖拽行为干扰。
然后,组件部分大致是这样写的:
<script setup lang="ts">
import { ref } from 'vue'
const dragenter = ref(false)
function handleDragEnter() {
dragenter.value = true
}
function handleDragLeave() {
dragenter.value = false
}
function handleDrop(event: DragEvent) {
dragenter.value = false
const files = event.dataTransfer?.files
console.log(files)
}
</script>
<template>
<div
@dragenter.prevent="handleDragEnter"
@dragleave.prevent="handleDragLeave"
@dragover.prevent
@drop.prevent="handleDrop"
>
拖动至此区域上传
</div>
</template>
不过这个方案有个缺点:拿到的是文件对象而不是文件的绝对路径。虽然可以通过其它的方案解决,但我更希望能一步到位,直接拿到文件的路径,方便后续处理。
Tauri 实现方案
<script setup lang="ts">
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { onMounted, ref, useTemplateRef } from 'vue'
const dropRef = useTemplateRef('drop')
const dragenter = ref(false)
onMounted(() => {
getCurrentWebviewWindow().onDragDropEvent(({ payload }) => {
const { type } = payload
if (type === 'over') {
const { x, y } = payload.position
if (dropRef.value) {
const { left, right, top, bottom } = dropRef.value.getBoundingClientRect()
const inBoundsX = x >= left && x <= right
const inBoundsY = y >= top && y <= bottom
dragenter.value = inBoundsX && inBoundsY
}
} else if (type === 'drop' && dragenter.value) {
dragenter.value = false
console.log('dropped', payload.paths)
} else {
dragenter.value = false
}
})
})
</script>
<template>
<div ref="drop">
拖动至此区域上传
</div>
</template>
这样一来,不仅可以判断文件是否拖拽到了指定区域,还能直接获取绝对路径。