以前写了一篇文章 《前端粘贴复制还能这样玩》,其中涉及到DataTransfer
,下面我们来了解一下DataTransfer
对象。
DataTransfer
对象存在哪些事件对象中
目前就发现拖拽相关事件和paste
事件的事件对象中包含DataTransfer
对象。
DataTransfer
对象介绍
在mdn中介绍DataTransfer
对象用于保存拖动并放下(drag and drop)过程中的数据。但是paste
事件对象中clipboardData
也是一个DataTransfer
。
dropEffect
获取当前选定的拖放操作类型或者设置的为一个新的类型。值必须为none
(项目可能禁止拖放),copy
(在新位置生成源项的副本),link
(在新位置建立源项目的链接) 或move
(将项目移动到新位置)。它设置的属性表示鼠标拖动的视觉效果,所以我们可以在dragover, dragenter
中进行设置该值。effectAllowed
设置源元素(被拖动的元素)允许的拖动效果。none
(此项表示不允许放下)、copy
(源项目的复制项可能会出现在新位置。)、copyLink
(允许 copy 或者 link 操作。)、copyMove
(允许 copy 或者 move 操作。)、link
(可以在新地方建立与源的链接。)、linkMove
(允许 link 或者 move 操作。)、move
(一个项目可能被移动到新位置。)、all
(允许所有的操作。)、uninitialized
(效果没有设置时的默认值,则等同于 all。) 设置对应的属性有对应的效果。即可以限制我们拖动的结果。所以一般在dragstart
中进行设置。
effectAllowed和dropEffect
相互影响。二者的值需要设置交集。否则拖动是没有效果的。 想要查看效果可以看mdn demo
files
获取拖动和粘贴的文件(File)对象列表。这里的文件数据也会保存到items
中,以DataTransferItem
对象形式存在。items
拖动和粘贴所产生的数据(DataTransferItem)集合。内部包含kind, type
两个属性。types
拖动和粘贴所产生的数据的类型。例如文本(text/plain), 图片,文件资源(Files)
setData(type, value)
设置拖动所需要的数据源,会加入到items
属性集合中。注意设置相同类型type
的数据会覆盖。
getData(type)
通过指定的type
获取对应的数据源。clearData(type)
清除指定type
的数据源,如果不指定type
则清空所有数据,该方法只有在dragstart
事件中使用有效。setDragImage(imgElement, xOffset, yOffset)
修改拖动时的图像,一般没啥用,除非你用到了。
DataTransferItem
(DataTransfer.items每一项)对象介绍
最主要的是我们应该关注items
中的数据对象,即DataTransferItemList
对象,它内部包含着粘贴和拖拽的DataTransferItem
对象。
我们来看下DataTransferItem
对象中属性和方法
kind
拖拽或者粘贴项的种类,string
或是file
。type
拖拽或者粘贴项的类型,一般是一个 MIME 类型。
getAsFile()
如果DataTransferItem
是一个文件,那DataTransferItem.getAsFile()
方法将返回拖拽或者粘贴项数据的File
对象。如果拖拽项的数据不是一个文件,则返回null
。
getAsFileSystemHandle()
返回一个Promise, 可以用于判断当前粘贴和拖拽本地磁盘资源项是文件(FileSystemFileHandle
)还是文件夹(FileSystemDirectoryHandle
)。相比较直接通过kind, type
可以更具体的参看类型。
如果是文件可以调用getFile()
方法获取文件对象。如果是文件夹可以调用getFileHandle()
,返回指定名称的FileSystemFileHandle
对象然后再进行处理。
getAsString(callback)
如果DataTransferItem
是一个字符串,可以在回调中获取粘贴或者拖拽的字符串的值。如果是文件资源那么回调将不会执行。
粘贴的测试代码
js 代码解读复制代码 "true">
我是可输入文本的div
<script>
const div = document.getElementsByTagName("div")[0]
// 这个事件只作用于可编辑的dom元素上。
// 如果元素都没有设置contenteditable="true",那么将作用于整个网页。
div.addEventListener("paste", async function (e) {
console.log("粘贴", e.clipboardData.items[0])
// console.log("查看当前粘贴本地的内容是文件还是文件夹", await e.clipboardData.items[0].getAsFileSystemHandle())
// e.clipboardData.items[0].getAsString((res => {
// console.log("获取粘贴的字符串值", res)
// }))
// console.log("粘贴文件返回文件对象", e.clipboardData.items[0].getAsFile())
const fileOrDir = await e.clipboardData.items[0].getAsFileSystemHandle()
if(fileOrDir.kind === "file") {
console.log("获取文件对象", await fileOrDir.getFile())
}
})
script>
拖拽的测试代码
js 代码解读复制代码 "img-container">
<img id="img" src="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" alt="" draggable="true" width="100">
<script>
/**
*
*
- dragstart`: 开始拖拽对象时触发。在这里开始传递一些源数据。`e.dataTransfer.setData()`
*
- `dragover`: 当被拖拽元素**未离开**可释放目标元素上时,触发该事件。**在拖拽的过程中。**
- `dragleave`: 当被拖拽元素**离开**可释放目标元素上时,触发该事件。
- `drop`: 拖拽元素拖拽到可释放目标对象释放后触发。即在这边获取拖拽元素时传入的一些源数据,做一些其他的逻辑处理。通过`e.dataTransfer.getData()`来获取对应的属性。
*
**/
const target = document.getElementById("img-container")
const source = document.getElementById("img")
source.ondragstart = function(e) {
console.log("开始")
e.dataTransfer.setData('text/html', "覆盖拖动时产生的text/html类型数据");
e.dataTransfer.setData('text/plain', 'plain text');
// 发送数据
e.dataTransfer.setData('imgName', "test")
e.dataTransfer.setData('imgType', "png")
e.dataTransfer.setData('imgPath', e.target.currentSrc)
e.dataTransfer.clearData()
}
// target.ondragenter = function(e) {
// console.log("e", e)
// }
// 进入目标元素时触发
target.addEventListener("dragover", (event) => {
console.log("进入目标元素移动时触发")
// prevent default to allow drop
event.preventDefault();
});
// 在使用drop事件之前,需要注册dragover事件。并且需要阻止默认事件。
target.ondrop = async function(e) {
console.log("拖拽", e.dataTransfer.items, e.dataTransfer.items[0], e.dataTransfer.items[1], e.dataTransfer.items[2], e.dataTransfer.items[3], e.dataTransfer.items[4])
console.log("查看当前拖拽本地的内容是文件还是文件夹", await e.dataTransfer.items[0].getAsFileSystemHandle())
e.dataTransfer.items[0].getAsString((res => {
console.log("获取拖拽的字符串值0", res)
}))
e.dataTransfer.items[1].getAsString((res => {
console.log("获取拖拽的字符串值1", res)
}))
e.dataTransfer.items[2].getAsString((res => {
console.log("获取拖拽的字符串值2", res)
}))
e.dataTransfer.items[3].getAsString((res => {
console.log("获取拖拽的字符串值2", res)
}))
console.log("拖拽数据中的文件", e.dataTransfer.files, e.dataTransfer.files[0])
console.log("拖拽文件返回文件对象", e.dataTransfer.items[0].getAsFile())
console.log("通过getData(type)获取数据源", e.dataTransfer.getData('text/html'))
// console.log("e", e, e.dataTransfer.files[0], e.dataTransfer.items[0], e.dataTransfer.types[0])
// // 在可拖拽的区域拖拽到指定的对象时触发
// const imgName = e.dataTransfer.getData('imgName')
// const imgType = e.dataTransfer.getData('imgType')
// const imgPath = e.dataTransfer.getData('imgPath')
// // 我们拖动文件到别的文件夹时,只是将文件对象加入到目的文件列表中。
// const img = document.createElement("img")
// img.setAttribute("src", imgPath)
// img.setAttribute("name", imgName)
// target.appendChild(img)
// img.style.width = "100px"
// img.style.height = "100px"
// document.body.removeChild(source)
}
script>
了解上面的这些操作我们就很容易的拿到文件对象上传给服务器了。
html 代码解读复制代码// index.html
<div contenteditable="true">
我是可输入文本的div
div>
<script>
const div = document.getElementsByTagName("div")[0]
div.addEventListener("paste", async function (e) {
console.log("粘贴", e.clipboardData.items[0], e.clipboardData.files[0])
const formData = new FormData()
formData.append("file", e.clipboardData.files[0])
let config = {
headers: {'Content-Type': 'multipart/form-data'}
}
axios.post("http://127.0.0.1:3000/login/file", formData, config).then(res => {
console.log("res",res)
})
})
script>
后端我们是通过nestjs进行处理文件上传的。这里需要配合multer
库去实现。
js 代码解读复制代码 @Post('file')
@UseInterceptors(
AnyFilesInterceptor({
storage: diskStorage({
destination: 'uploads',
filename: (req, file, cb) => {
const randomName = Array(32)
.fill(null)
.map(() => Math.round(Math.random() * 16).toString(16))
.join('');
return cb(null, `${randomName}${extname(file.originalname)}`);
},
}),
}),
)
uploadCopyImgs(@UploadedFiles() files: any) {
console.log(files);
return `文件上传成功文件名为: ${files[0].filename}`;
}
往期年度总结
往期文章
- Nest装饰器全解析
- Nest世界中的AOP
- Nestjs如何解析http传输的数据
- 如何理解js的DOM事件系统
- 半年没看vue官网,3.5刚刚发布,趁机整理下
- 啊,你还在找一款强大的表格组件吗?
- 前端大量数据层级展示及搜索定位预览
- 如何从0开始认识m3u8(提取,解析及下载)
- 展示大量数据节点(tree),引发的一次性能排查
- ts装饰器的那点东西
- 这是你所知道的ts类型断言和类型守卫吗?
- TypeScript官网内容解读
- 经常使用ts的你,知道这些内容?
- 你有了解过原生css的scope?
- 现在比较常用的移动端调试你知道哪些?
- 众多跨标签页通信方式,你知道哪些?(二)
- 众多跨标签页通信方式,你知道哪些?
- 反调试吗?如何监听devtools的打开与关闭
- 因为原生,选择一家公司(前端如何防笔试作弊)
- 结合开发,带你熟悉package.json与tsconfig.json配置
- 如何优雅的在项目中使用echarts
- 如何优雅的做项目国际化
- 近三个月的排错,原来的憧憬消失喽
- 带你从0开始了解vue3核心(运行时)
- 带你从0开始了解vue3核心(computed, watch)
- 带你从0开始了解vue3核心(响应式)
- 3w+字的后台管理通用功能解决方案送给你
- 入职之前,狂补技术,4w字的前端技术解决方案送给你(vue3 + vite )
专栏文章
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论, 支持一下博主~
公众号:全栈追逐者,不定期的更新内容,关注不错过哦!
评论记录:
回复评论: