完成托拽上传功能学到的技术点
一、拖拽获取到文件 a). 原理调用原生js提供的 drop系列的事件
- dragentetr 当被鼠标拖动的对象进入其容器范围内时触发此事件
- dragleave 当被鼠标拖动的对象离开其容器范围内时触发此事件
- drop 当被鼠标拖动的对象在容器范围内时被放下时触发此事件
- dragover 当某被拖动的对象在另一对象容器范围内拖动时触发此事件 使用时需要给body绑定以上四个事件, 取消浏览器的默认行为(打开文件);
function clearDefault (event) {
var e = event || window.event
e.preventDefault()
}
document.addEventListener('dragentetr', clearDefault)
document.addEventListener('dragleave', clearDefault)
document.addEventListener('drop', clearDefault)
document.addEventListener('dragover', clearDefault)
b). 在dom上指定一个区域作为我们要拖入文件的区域。一般是一个div;
<div id="dropBox"></div>
为改div绑定上事件,
- dragenter 进入事件, 提示用户可以放开鼠标
- dragleave 离开区域时, 提示文字恢复为将文件拖至此区域
- drop 文件进入此区域时, 可以通过e.dataTransfer.files 这个数组访问到进入次区域的所有文件, 是一个索引数组;可以访问到文件的一些信息
var div = document.querySelector('#dropBox')
div.addEventListener('dragenter', function (event) {
var e = event || window.event
e.preventDefault()
this.innerHTML = '请释放鼠标'
this.style.borderColor = 'green'
})
div.addEventListener('dragleave', function (event) {
var e = event || window.event
e.preventDefault()
this.style.borderColor = 'red'
this.innerHTML = '请将文件拖在此区域'
})
div.addEventListener('drop', function (event) {
var e = event || window.event
e.preventDefault()
var files = e.dataTransfer.files // 这个是一个索引数组 => [file1, file2]
// 每个file拥有以下信息 注意: 它们都是只读的
var file = {
lastModified: 1500618905073, // =>这个代表是最后修改时间 格式是时间戳
lastModifiedDate: 'Fri Jul 21 2017 14:35:05 GMT+0800 (中国标准时间)', // =>同样也是最后修改的时间 格式是Date形式
name: '测试文档.docx', // =>文件的名字
size: 969331, // =>文件的大小 单位是B 如有需要的话, 需要换算为别的单位
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // =>文件的类型
webkitRelativePath: ''// => MDN上面说 它返回 File 相关的 path 或 URL。
}
// 这里我们只是单文件上传, 只取files中第一个文件
file = files[0]
// 获取文件的路径采用的是另外一个方法 window.URL.createObjectURL(file) 它的作用是创建一个可以被浏览器识别的路径 是一个网络地址形式的路径信息
var filePath = window.URL.createObjectURL(file)
// 根据上面说的我们在控制台打印文件的信息
console.log('文件名: ' + file.name)
console.log('大小: ' + bytesToSize(file.size))
console.log('类型: ' + file.type)
console.log('路径: ' + filePath)
/*
*到这里已经获取到了文件, 可以使用ajax
*上传到服务器, 也可以使用H5的
*FileReader
*读取它的内容
*/
})
/*
*在网上找的换算字节的函数
*参数: bytes number 待转换的数字
*输出: 合理的计算后并输出单位 B KB MB...
*/
function bytesToSize (bytes) {
if (bytes === 0) return '0 B'
var k = 1000 // or 1024
var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
var i = Math.floor(Math.log(bytes) / Math.log(k))
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]
}
二、XMLHttpRequest Level 2 XMLHttpRequest Level 2 我喜欢叫它ajax2代 它与第一代相比增加了很多实用的东西这里不做详细说明
- 跨域访问, 在后端加上跨域响应头 响应头代码: Access-Control-Allow-Origin: "你自己的域名" ps这篇文章不再做详细的说明
- 可以获取服务器端的二进制数据。范例代码: xhr.responseType = 'blob' ; ps这个我也不是很理解, 暂时做为记录
- 可以获取数据传输的进度信息。待会下面会详细说明这个。
- timeout 属性, 等待一定时间以后,请求未结束, 会触发ontimeout 事件, 认为此次请求超时, 失败。
- FormData 属性 自己在js中创建form形式的数据, 而不用像以前那样在html中创建一个不显示的form。待会下面会详细说明这个。 还有很多别的功能, 我会慢慢的补充...
// 创建一个ajax对象
var xhr = new XMLHttpRequest()
xhr.open('GET', 'test.do')
xhr.send()
获取数据传输进度信息 上传于下载调用的是不用对象的onprogress事件 上传触发的是xhr.upload对象的 onprogress事件 下载触发的是xhr对象的onprogress事件
xhr.onprogress = updateProgress
xhr.upload.onprogress = updateProgress
function updateProgress (event) {
if (event.lengthComputable) {
// event.loaded 已经发送 / 下载的数据量
// event.total 文件的总数据量
var completedPercent = event.loaded / event.total
console.log(completedPercent)
}
}
/*
* 还有一些对应的事件, 这里只提一下
* load事件:传输成功完成。
* abort事件:传输被用户取消。
* error事件:传输中出现错误。
* loadstart事件:传输开始。
* loadEnd事件:传输结束,但是不知道成功还是失败。
*/
timeout 请求超时的相关设置
xhr.timeout = 5000 // 单位ms
xhr.ontimeout = function () { // 请求发起后的5s内为完成 就会结束请求并触发该事件
console.log('请求错误')
}
三、FormData 说明 在以前我们的开发中, 获取一个form的input的值时 采用自己定义一个json 键为与后端定义好的name, 值为用jquery选择器找到对应的input,用val()方法获取值。 现在有了FormData以后我们不需要用jquery去获取一个input的val()值, 像下面这样: 在html中写一个form表单
<form id="submit" action="http://test">
<input type="text" name="username">
<input type="text" name="pwd">
<input type="submit" value="提交">
</form>
在js中我们这样写
var submit = document.querySelector('#submit') // 获取到id是submit的表单
submit.onsubmit = function () {
var data = new FormData(submit) // 初始化一个formdata对象
/*
* 这里我们已经获取到了id为submit中所有input的值
* 此时我们console.log(data)的话在控制台只能看到一个空对象。
* 这里我们用ajax发起请求的时候,在chrome的控制台的network选项卡中可以看到它内部的东西
*/
// 如果需要在data中临时加一个值的时候可以这样的形式加入
// data.append('name', 'value')
data.append('enail', '345565@qq.com')
}
现在就可以上传我在上边拖拽拿到的文件了
function ajaxPushFile (file) {
// 这里的file就是上面我们获取到的file
if (!file) {
return false
}
var data = new FormData() // 初始化一个formdata对象 这里没有from元素就不传值
data.append('files', file) // 将文件加入formdata中
var xhr = new XMLHttpRequest() // 初始化ajax
xhr.open('POST', 'http://test')
xhr.timeout = 10000 // 设置超时
xhr.responseType = 'text' // 设置响应返回的数据格式
xhr.onreadystatechange = function (e) {
if (this.readyState === 4 && this.status === 200) {
// 获取返回的值
}
}
xhr.ontimeout = function () { // 超时的回调
alert('上传失败')
}
xhr.upload.onprogress = updateProgress // 获取上传进度
function updateProgress (event) {
if (event.lengthComputable) {
// event.loaded 已经发送 / 下载的数据量
// event.total 文件的总数据量
var completedPercent = event.loaded / event.total
console.log(completedPercent)
}
}
xhr.send(data)
}
到此 拖拽功能完成 这个功能用到了拖拽事件 与 ajax2 与 FormData 技术点
页面全部代码:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<style>
* {
margin: 0;
padding: 0;
}
#drop {
width: 500px;
height: 400px;
border: 10px dotted red;
}
</style>
<body>
<div id="drop">
请将文件拖拽到这里
</div>
</body>
<script>
function clearDefault(event) {
var e = event || window.event
e.preventDefault()
}
document.addEventListener('dragentetr', clearDefault)
document.addEventListener('dragleave', clearDefault)
document.addEventListener('drop', clearDefault)
document.addEventListener('dragover', clearDefault)
var div = document.querySelector('#drop')
div.addEventListener('dragenter', function(event) {
var e = event || window.event
e.preventDefault()
this.innerHTML = '请释放鼠标'
this.style.borderColor = 'green'
})
div.addEventListener('dragleave', function(event) {
var e = event || window.event
e.preventDefault()
this.style.borderColor = 'red'
this.innerHTML = '请将文件拖在此区域'
})
div.addEventListener('drop', function(event) {
var e = event || window.event
e.preventDefault()
var files = e.dataTransfer.files // 这个是一个索引数组 => [file1, file2]
// 每个file拥有以下信息 注意: 它们都是只读的
var file = {
lastModified: 1500618905073, // =>这个代表是最后修改时间 格式是时间戳
lastModifiedDate: 'Fri Jul 21 2017 14:35:05 GMT+0800 (中国标准时间)', // =>同样也是最后修改的时间 格式是Date形式
name: '测试文档.docx', // =>文件的名字
size: 969331, // =>文件的大小 单位是B 如有需要的话, 需要换算为别的单位
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // =>文件的类型
webkitRelativePath: '' // => MDN上面说 它返回 File 相关的 path 或 URL。
}
// 这里我们只是单文件上传, 只取files中第一个文件
file = files[0]
// 获取文件的路径采用的是另外一个方法 window.URL.createObjectURL(file) 它的作用是创建一个可以被浏览器识别的路径 是一个网络地址形式的路径信息
var filePath = window.URL.createObjectURL(file)
// 根据上面说的我们在控制台打印文件的信息
console.log('文件名: ' + file.name)
console.log('大小: ' + bytesToSize(file.size))
console.log('类型: ' + file.type)
console.log('路径: ' + filePath)
/*
*到这里已经获取到了文件, 可以使用ajax
*上传到服务器, 也可以使用H5的
*FileReader
*读取它的内容
*/
})
/*
*在网上找的换算字节的函数
*参数: bytes number 待转换的数字
*输出: 合理的计算后并输出单位 B KB MB...
*/
function bytesToSize(bytes) {
if (bytes === 0) return '0 B'
var k = 1000 // or 1024
var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
var i = Math.floor(Math.log(bytes) / Math.log(k))
return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]
}
function ajaxPushFile (file) {
// 这里的file就是上面我们获取到的file
if (!file) {
return false
}
var data = new FormData() // 初始化一个formdata对象 这里没有from元素就不传值
data.append('files', file) // 将文件加入formdata中
var xhr = new XMLHttpRequest() // 初始化ajax
xhr.open('POST', 'http://test')
xhr.timeout = 10000 // 设置超时
xhr.responseType = 'text' // 设置响应返回的数据格式
xhr.onreadystatechange = function (e) {
if (this.readyState === 4 && this.status === 200) {
// 获取返回的值
}
}
xhr.ontimeout = function () { // 超时的回调
alert('上传失败')
}
xhr.upload.onprogress = updateProgress // 获取上传进度
function updateProgress (event) {
if (event.lengthComputable) {
// event.loaded 已经发送 / 下载的数据量
// event.total 文件的总数据量
var completedPercent = event.loaded / event.total
console.log(completedPercent)
div.innerHTML = '已完成: ' + (completedPercent * 100) + '%'
}
}
xhr.send(data)
}
</script>
</html>