We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
说明:请使用该Token:1562835370187访问本文Demo,或者点击访问。
本文通过实现(文本/文件)拖动预览功能全面、深入分析整个过程涉及的对象及其API,增强我们对文件类数据的理解和应用。介绍的内容包括:
DataTransfer
File
Blob
DataTransfer对象用来保存在一个拖放操作中被拖动的数据,它可以包含一个或多个数据项,每一个数据项又可以有一种或多种数据类型。
DataTransfer对象的属性分为标准属性和gecko属性。其中,标准属性是所有现代浏览器都支持的,gecko属性则只有gecko内核的浏览器才支持。相应地,DataTransfer的方法也有标准方法和gecko方法之分。
gecko
关于DataTransfer对象的Gecko属性和方法,移步这里了解。
用户在拖动元素或者文本时,每隔几百毫秒就会触发拖动事件。拖动事件类型有:
document.addEventListener('dragstart', evt => { console.log('dragstart'); }); document.addEventListener('dragenter', evt => { console.log('dragenter'); }); document.addEventListener('dragleave', evt => { console.log('dragleave'); }); document.addEventListener('dragover', evt => { event.preventDefault(); console.log('dragover'); }); document.addEventListener('drop', evt => { console.log('drop'); }); document.addEventListener('dragend', evt => { console.log('dragend'); });
拖动事件是绑定在元素身上的,上述示例代码绑定在了document对象上,则对整个文档页面的拖动事件生效;但在实际应用中,我们更多是劫持某个输入区域的拖放操作,譬如:
document
$inputBox.addEventListener'drop', evt) => { evt.preventDefault() console.log('drop') }, { capture: false, passive: false })
特别地,拖动事件有严格的触发次序: 假定有一个拖放区域,拖动外部元素/文本到该区域,可能触发的拖动事件次序有如下两种类型: 或是
DataTransfer对象提供了dropEffect和effectAllowed两个属性,允许我们自定义拖动过程中鼠标的类型,其中,dropEffect的值受effectAllowed制约,只能设置effectAllowed允许设置的值。
dropEffect
effectAllowed
effectAllowed只能在dragstart事件中设置,在其他事件中设置不会生效。不同取值代表的含义:
dragstart
document.addEventListener('dragstart', (e) => { e.dataTransfer.effectAllowed = 'none' }, { capture: false, passive: false })
如上设置后,文档上的元素/文本将被禁止拖放。但仍然可以触发除drop以外的一系列的拖动事件。
drop
dropEffect的取值受effectAllowed的制约,只允许被设置effectAllowed指定的值。可能的取值有:move、copy、link、none。dropEffect一般在dragenter和dragover事件中设置,在其他事件中设置也不会生效。
move
copy
link
none
dragenter
dragover
$Ele.addEventListener('dragover', (e) => { e.preventDefault() e.dataTransfer.dropEffect = 'move|move|copy|link' }, { capture: false, passive: false })
点击这里玩一玩:拖动操作鼠标类型demo
通过该API可以自定义拖动操作中鼠标的背景图片,这个方法必须在dragstart中调用:
const img = new Image() img.src = './bg.png' document.addEventListener('dragstart', (e) => { e.dataTransfer.setDragImage(img, 5, 5) }, { capture: false, passive: false })
如下图,将文本拖动到输入框,在鼠标底下会紧跟一张背景图片:
在介绍截取拖动数据之前,有必要先了解下dataTransferItem对象。dataTransferItem对象表示一个拖动数据项,比如拖动的文本、图片等数据。它有两个用于描述数据类型的只读属性,还有用于将dataTransferItem数据转换为对应类型的数据(字符串、文件等)的一系列方法。如下表:
dataTransferItem
在一个拖动操作中,可能包含了多项数据(比如同时拖动了多个文件),这个时候就需要一个列表去描述这一组拖动数据,这个列表,就是DataTransferItemList对象,这是一个类数组的对象(有一个length属性,只读,还有add()、remove()和clear()等API)。
DataTransferItemList
length
add()
remove()
clear()
对拖动数据进行劫持一般在dragstart和drop阶段处理,因为这两个阶段的事件都是一次性,不会多次触发,不会造成性能问题。例如,用setData设置固定的文案去覆盖被拖动的文本内容:
setData
document.addEventListener('dragstart', e => { e.dataTransfer.setData('text/plain', '期望覆盖的文案') }, { capture: false, passive: false })
在drop阶段我们可以截取到拖动数据,然后做二次处理。但对于不同类型的数据截取,会有一些差异。
对于字符串类型数据,最简单的是通过getData方法获取(该方法无法获取文件类数据)。例如,获取拖动的纯文本内容:
getData
$Ele.addEventListener('drop', (e) => { e.preventDefault() console.log(e.dataTransfer.getData('text')) }, { capture: false, passive: false })
这种方式获取的是拖动的纯文本内容: 当然,通过指定字符串的格式,还可以获取富文本内容:
console.log(e.dataTransfer.getData('text/plain'))
这种方式获取的是拖动文案的DOM节点及其祖先节点内容: 另外一种是通过dataTransferItem对象获取,稍后再介绍。
DOM
DataTransfer对象有一个files属性,用于存储拖动文件的列表数据。数据项就是一个File对象数据,可以直接取出。
files
$Ele.addEventListener('drop', (e) => { e.preventDefault() const files = e.dataTransfer.files || [] if(files.length) { // do something... } }, false)
在前面dataTransfer对象的标准属性中介绍过,items属性的值是一个DataTransferItemList对象,通过for循环从里面逐个取出数据,并判断dataTransferItem的kind属性值作不同的操作:
dataTransfer
items
for
kind
const transferItems = e.dataTransfer.items for(let i = 0; i < transferItems.length; i++) { const item = transferItems[i] if(item.kind === 'string') { // 处理字符串数据 item.getAsString(str => console.log(str)) } else if (item.kind === 'file') { // 处理文件数据 const file = item.getAsFile() // ... } }
通过上面的方式截取到拖动数据之后,我们可以根据需要对文件数据进行预览或发送。
根据上文可知,通过getAsFile API我们获取到了拖动的文件,返回的是一个File对象。里面包含了文件类型(image/png等)、名字和大小等信息。File对象是特殊类型的Blob,继承了Blob的属性和方法,File里面主要使用的属性有:
getAsFile
image/png
Blob是一个不可变、表示原始数据的类文件对象,拥有type和size两个只读属性,可以通过FileReader和Response读取Blob里面的数据。譬如,一个图片文件,被FileReader以不同的数据格式读取:
type
size
FileReader
const reader = new FileReader() reader.addEventListener("load", () => { console.log(reader.result) }, false) reader.readAsDataURL(file) // reader.readAsArrayBuffer(file) // reader.readAsText(file[, encoding])
返回一串data:[MIME type];开头的base64编码串,读取的data URL数据一般用在图片预览上:
data:[MIME type];
ArrayBuffer
utf-8
现在,根据截取的数据,我们需要继续实现:如果是图片,则对其进行预览。预览的方式有Data URL和Blob URL两种。 Data URL的方式在File&Blob概述章节已经介绍了,使用FileReader.readAsDataURL()方法即可。
FileReader.readAsDataURL()
URL对象可以用来构造、解析和编码url,它提供了一个静态方法createObjectURL(),方法的参数仅限于File、Blob和MediaSource这三种类型的对象,用于将类文件对象转化成URL字符串(形如:blob:http://localhost:8080/c61a0313-2e45-4adc-a40e-fbbffd4c84ba),该字符串指向对应(文件)对象的引用。
URL
createObjectURL()
MediaSource
blob:http://localhost:8080/c61a0313-2e45-4adc-a40e-fbbffd4c84ba
// 前面我们通过截取拿到了file对象数据 const { name, size } = file const url = URL.createObjectURL(file) this.previewObj = { name, size, src: url }
调用createObjectURL()方法有两个特点:
createObjectURL
从规范和内存管理的角度讲,每一次执行createObjectURL,我们需要手动释放内存(但实际应用中影响并不大):
// 在文件加载就绪之后卸载URL实例的引用 img.onload = function() { URL.revokeObjectURL(this.src); }
base64
最后,
参考:
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
本文通过实现(文本/文件)拖动预览功能全面、深入分析整个过程涉及的对象及其API,增强我们对文件类数据的理解和应用。介绍的内容包括:
DataTransfer
对象介绍及API应用File
和Blob
对象介绍DataTransfer对象
DataTransfer
对象用来保存在一个拖放操作中被拖动的数据,它可以包含一个或多个数据项,每一个数据项又可以有一种或多种数据类型。DataTransfer
对象的属性分为标准属性和gecko属性。其中,标准属性是所有现代浏览器都支持的,gecko
属性则只有gecko
内核的浏览器才支持。相应地,DataTransfer
的方法也有标准方法和gecko
方法之分。DataTransfer的标准属性
DataTransfer的标准方法
关于DataTransfer对象的Gecko属性和方法,移步这里了解。
拖动事件
用户在拖动元素或者文本时,每隔几百毫秒就会触发拖动事件。拖动事件类型有:
拖动事件是绑定在元素身上的,上述示例代码绑定在了
document
对象上,则对整个文档页面的拖动事件生效;但在实际应用中,我们更多是劫持某个输入区域的拖放操作,譬如:特别地,拖动事件有严格的触发次序:
假定有一个拖放区域,拖动外部元素/文本到该区域,可能触发的拖动事件次序有如下两种类型:
或是
拖动效果
DataTransfer
对象提供了dropEffect
和effectAllowed
两个属性,允许我们自定义拖动过程中鼠标的类型,其中,dropEffect
的值受effectAllowed
制约,只能设置effectAllowed
允许设置的值。effectAllowed
effectAllowed
只能在dragstart
事件中设置,在其他事件中设置不会生效。不同取值代表的含义:如上设置后,文档上的元素/文本将被禁止拖放。但仍然可以触发除
drop
以外的一系列的拖动事件。dropEffect
dropEffect
的取值受effectAllowed
的制约,只允许被设置effectAllowed
指定的值。可能的取值有:move
、copy
、link
、none
。dropEffect
一般在dragenter
和dragover
事件中设置,在其他事件中设置也不会生效。点击这里玩一玩:拖动操作鼠标类型demo
setDragImage
通过该API可以自定义拖动操作中鼠标的背景图片,这个方法必须在
dragstart
中调用:如下图,将文本拖动到输入框,在鼠标底下会紧跟一张背景图片:
dataTransferItem对象
在介绍截取拖动数据之前,有必要先了解下
dataTransferItem
对象。dataTransferItem
对象表示一个拖动数据项,比如拖动的文本、图片等数据。它有两个用于描述数据类型的只读属性,还有用于将dataTransferItem
数据转换为对应类型的数据(字符串、文件等)的一系列方法。如下表:在一个拖动操作中,可能包含了多项数据(比如同时拖动了多个文件),这个时候就需要一个列表去描述这一组拖动数据,这个列表,就是
DataTransferItemList
对象,这是一个类数组的对象(有一个length
属性,只读,还有add()
、remove()
和clear()
等API)。截取拖动数据
对拖动数据进行劫持一般在
dragstart
和drop
阶段处理,因为这两个阶段的事件都是一次性,不会多次触发,不会造成性能问题。例如,用setData
设置固定的文案去覆盖被拖动的文本内容:在
drop
阶段我们可以截取到拖动数据,然后做二次处理。但对于不同类型的数据截取,会有一些差异。字符串类型数据
对于字符串类型数据,最简单的是通过
getData
方法获取(该方法无法获取文件类数据)。例如,获取拖动的纯文本内容:这种方式获取的是拖动的纯文本内容:
当然,通过指定字符串的格式,还可以获取富文本内容:
这种方式获取的是拖动文案的
DOM
节点及其祖先节点内容:另外一种是通过
dataTransferItem
对象获取,稍后再介绍。文件类型数据
DataTransfer
对象有一个files
属性,用于存储拖动文件的列表数据。数据项就是一个File
对象数据,可以直接取出。从items属性中截取
在前面
dataTransfer
对象的标准属性中介绍过,items
属性的值是一个DataTransferItemList
对象,通过for
循环从里面逐个取出数据,并判断dataTransferItem
的kind
属性值作不同的操作:通过上面的方式截取到拖动数据之后,我们可以根据需要对文件数据进行预览或发送。
File&Blob概述
根据上文可知,通过
getAsFile
API我们获取到了拖动的文件,返回的是一个File
对象。里面包含了文件类型(image/png
等)、名字和大小等信息。File
对象是特殊类型的Blob
,继承了Blob
的属性和方法,File
里面主要使用的属性有:Blob
是一个不可变、表示原始数据的类文件对象,拥有type
和size
两个只读属性,可以通过FileReader和Response读取Blob
里面的数据。譬如,一个图片文件,被FileReader
以不同的数据格式读取:返回一串
data:[MIME type];
开头的base64编码串,读取的data URL数据一般用在图片预览上:ArrayBuffer
格式读取,返回一个ArrayBuffer
对象读取的
ArrayBuffer
数据一般用于图片的二次处理,譬如转换jepg格式图片为png。utf-8
的编码格式读取文本内容(图片这么读下去,会乱码的)实现图片预览
现在,根据截取的数据,我们需要继续实现:如果是图片,则对其进行预览。预览的方式有Data URL和Blob URL两种。
Data URL的方式在File&Blob概述章节已经介绍了,使用
FileReader.readAsDataURL()
方法即可。createObjectURL
URL
对象可以用来构造、解析和编码url,它提供了一个静态方法createObjectURL()
,方法的参数仅限于File
、Blob
和MediaSource
这三种类型的对象,用于将类文件对象转化成URL字符串(形如:blob:http://localhost:8080/c61a0313-2e45-4adc-a40e-fbbffd4c84ba
),该字符串指向对应(文件)对象的引用。调用
createObjectURL()
方法有两个特点:document
卸载之前,URL
对象实例会一直保持源对象的引用;createObjectURL
方法,会生成不同的URL对象实例。从规范和内存管理的角度讲,每一次执行
createObjectURL
,我们需要手动释放内存(但实际应用中影响并不大):Data URL与Blob URL的区别
base64
格式编码的图片内容,Blob URL表示的是(内存中/本地)图片文件的引用(这是本质区别);最后,
参考:
The text was updated successfully, but these errors were encountered: