实现拖拽上传功能, 学到的技术点总结

本文介绍如何使用原生JavaScript实现拖拽文件上传功能,并利用XMLHttpRequest Level 2和FormData进行文件上传,包括处理文件信息、进度反馈等。

完成托拽上传功能学到的技术点

一、拖拽获取到文件 a). 原理调用原生js提供的 drop系列的事件

  1. dragentetr 当被鼠标拖动的对象进入其容器范围内时触发此事件
  2. dragleave 当被鼠标拖动的对象离开其容器范围内时触发此事件
  3. drop 当被鼠标拖动的对象在容器范围内时被放下时触发此事件
  4. 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绑定上事件,

  1. dragenter 进入事件, 提示用户可以放开鼠标
  2. dragleave 离开区域时, 提示文字恢复为将文件拖至此区域
  3. 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代 它与第一代相比增加了很多实用的东西这里不做详细说明

  1. 跨域访问, 在后端加上跨域响应头 响应头代码: Access-Control-Allow-Origin: "你自己的域名" ps这篇文章不再做详细的说明
  2. 可以获取服务器端的二进制数据。范例代码: xhr.responseType = 'blob' ; ps这个我也不是很理解, 暂时做为记录
  3. 可以获取数据传输的进度信息。待会下面会详细说明这个。
  4. timeout 属性, 等待一定时间以后,请求未结束, 会触发ontimeout 事件, 认为此次请求超时, 失败。
  5. 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>

转载于:https://my.oschina.net/u/3105272/blog/1498982

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值