Vue实现带进度条的文件拖动上传功能


Posted in Javascript onFebruary 23, 2018

1. 基本界面

<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport"
   content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <link href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet">
 <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
 <style>
  .dropbox {
   border: .25rem dashed #007bff;
   min-height: 5rem;
  }
 </style>
 <title>Document</title>
</head>
<body>
<div id="app" class="m-5">
 <div class="dropbox p-3">
  <h2 class="text-center">把要上传的文件拖动到这里</h2>
 </div>
</div>
<script>
 new Vue({
  el: '#app',
  data: {},
  methods: {},
  mounted: function () {}
 });
</script>
</body>
</html>

Vue实现带进度条的文件拖动上传功能

2. 检测拖动事件

首先让页面支持文件拖拽,在 Vue 的 mounted() 函数中添加代码:

mounted: function () {
 var dropbox = document.querySelector('.dropbox');
 dropbox.addEventListener('dragenter', this.onDrag, false);
 dropbox.addEventListener('dragover', this.onDrag, false);
 dropbox.addEventListener('drop', this.onDrop, false);
}

当把文件拖动到浏览器的拖动区域时,会触发三种事件:

  1. 文件第一次进入拖动区时,触发 dragenter 事件
  2. 文件在拖动区来回拖拽时,不断触发 dragover 事件
  3. 文件已经在拖动区,并松开鼠标时,触发 drop 事件

实现拖动上传,我们只需要关心 drop 事件。不过另外两个事件也需要监听,目的是阻止浏览器默认行为。如果不阻止,那么把文件拖到浏览器时,浏览器就会自动下载这个文件(默认行为),drop 事件触发不出来。

事件的监听函数添加在 Vue 的 methods 对象中:

methods: {
 uploadFile: function (file) {
  console.log(file);
 },
 onDrag: function (e) {
  e.stopPropagation();
  e.preventDefault();
 },
 onDrop: function (e) {
  e.stopPropagation();
  e.preventDefault();
  var dt = e.dataTransfer;
  for (var i = 0; i !== dt.files.length; i++) {
   this.uploadFile(dt.files[i]);
  }
 }
},

onDrop() 函数中,通过 e.dataTransfer.files 可以拿到用户拖动到浏览器的文件的基本信息,uploadFile() 函数现在只这些信息打印了出来,可以了解到,拖动到浏览器的每个文件都是一个 File 对象:

Vue实现带进度条的文件拖动上传功能

3. 处理拖动事件

现在,我们要给 uploadFile() 函数增加功能,实现拖动文件时,拖动区出现文件名和一个上传进度条。

首先在 Vue 的 data 对象中定义 files 属性,用来保存所有拖动到浏览器中文件的名称。然后在uploadFile() 函数每当被调用时,把文件名和上传进度保存到 files 中:

data: {
 files: []
},
methods: {
 uploadFile: function (file) {
  var item = {
   name: file.name,
   uploadPercentage: 67
  };
  this.files.push(item);
 },
}

上传进度的功能在后面再介绍,先写一个固定值。

相应地,在HTML代码中,用 v-for 关键字显示 files 的每一项:

<div class="dropbox p-3">
 <h2 class="text-center">把要上传的文件拖动到这里</h2>
 <div class="border m-2 d-inline-block p-4" style="width:15rem" v-for="file in files">
  <h5 class="mt-0">{{ file.name }}</h5>
  <div class="progress">
   <div class="progress-bar progress-bar-striped"
     :style="{ width: file.uploadPercentage+'%' }"></div>
  </div>
 </div>
</div>

而且,“把要上传的文件拖动到这里” 的提示只在拖动区没有文件的时候才显示:

<h2 v-if="files.length===0" class="text-center">把要上传的文件拖动到这里</h2>

这样,拖动效果就有了:

Vue实现带进度条的文件拖动上传功能

4. 文件上传

接下来实现真正的文件上传,继续往 uploadFile() 函数添加代码:

uploadFile: function (file) {
 var item = {
  name: file.name,
  uploadPercentage: 67
 };
 this.files.push(item);
 var fd = new FormData();
 fd.append('myFile', file);

 var xhr = new XMLHttpRequest();
 xhr.open('POST', 'upload.php', true);
 xhr.send(fd);
},

这里用到了 FormData,把要上传的文件附在了 FormData 上,并通过AJAX方式发送给PHP端。PHP端代码:

if (isset($_FILES['myFile'])) {
 move_uploaded_file($_FILES['myFile']['tmp_name'], 'uploads/' . $_FILES['myFile']['name']);
 echo 'OK';
} else {
 echo 'No file specified';
}

现在刷新下页面,把电脑上的两个文件拖到浏览器中,PHP端会接收并保存文件到 uploads 目录:

Vue实现带进度条的文件拖动上传功能

提示:如果拖放时遇到PHP返回了No file specified,或者 $_FILES 为 NULL 的情况时,有可能是PHP限制了POST请求最大字节,或者限制了上传文件的体积。这时候需要调整下php.ini中的这两个配置:

post_max_size = 20M // POST请求的最大字节数
upload_max_filesize = 20M // 上传文件的最大体积

进度条的展示

基本的上传功能完成了,最后我们来完成进度条。每当AJAX请求发送了一段时间的数据时,都会生成一个 progress 事件,我们可以监听 progress 事件来知道当前的上传进度:

uploadFile: function (file) {
  ...
  xhr.upload.addEventListener('progress', function (e) {
    item.uploadPercentage = Math.round((e.loaded * 100) / e.total);
  }, false);
  xhr.send(fd);
},

e.loaded 代表当前AJAX发送了多少字节,e.total 代表AJAX总共要发送多少字节。通过这两个属性可以计算上传进度的百分比。

这样,一个带进度条的文件拖动上传功能就完成了。

附:完整代码

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
     content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
  <style>
    .dropbox {
      border: .25rem dashed #007bff;
      min-height: 5rem;
    }
  </style>
  <title>Document</title>
</head>
<body>
<div id="app" class="m-5">
  <div class="dropbox p-3">
    <h2 v-if="files.length===0" class="text-center">把要上传的文件拖动到这里</h2>
    <div class="border m-2 d-inline-block p-4" style="width:15rem" v-for="file in files">
      <h5 class="mt-0">{{ file.name }}</h5>
      <div class="progress">
        <div class="progress-bar progress-bar-striped"
           :style="{ width: file.uploadPercentage+'%' }"></div>
      </div>
    </div>
  </div>
</div>
<script>
  new Vue({
    el: '#app',
    data: {
      files: []
    },
    methods: {
      uploadFile: function (file) {
        var item = {
          name: file.name,
          uploadPercentage: 0
        };
        this.files.push(item);
        var fd = new FormData();
        fd.append('myFile', file);
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'upload.php', true);
        xhr.upload.addEventListener('progress', function (e) {
          item.uploadPercentage = Math.round((e.loaded * 100) / e.total);
        }, false);
        xhr.send(fd);
      },
      onDrag: function (e) {
        e.stopPropagation();
        e.preventDefault();
      },
      onDrop: function (e) {
        e.stopPropagation();
        e.preventDefault();
        var dt = e.dataTransfer;
        for (var i = 0; i !== dt.files.length; i++) {
          this.uploadFile(dt.files[i]);
        }
      }
    },
    mounted: function () {
      var dropbox = document.querySelector('.dropbox');
      dropbox.addEventListener('dragenter', this.onDrag, false);
      dropbox.addEventListener('dragover', this.onDrag, false);
      dropbox.addEventListener('drop', this.onDrop, false);
    }
  });
</script>
</body>
</html>

总结

以上所述是小编给大家介绍的Vue实现带进度条的文件拖动上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Jqgrid表格随窗口大小改变而改变的简单实例
Dec 28 Javascript
JS获取节点的兄弟,父级,子级元素的方法
Jan 09 Javascript
jQuery中get()方法用法实例
Dec 27 Javascript
js创建对象的方式总结
Jan 10 Javascript
JS实现文字链接感应鼠标淡入淡出改变颜色的方法
Feb 26 Javascript
CSS3 media queries结合jQuery实现响应式导航
Sep 30 Javascript
jquery把int类型转换成字符串类型的方法
Oct 07 Javascript
浅述Javascript的外部对象
Dec 07 Javascript
微信小程序实现图片懒加载的示例代码
Dec 13 Javascript
jQuery实现提交表单时不提交隐藏div中input的方法
Oct 08 jQuery
浅谈vue-router路由切换 组件重用挖下的坑
Nov 01 Javascript
浅谈Vue中render中的h箭头函数
Nov 07 Javascript
详解vue2.0 不同屏幕适配及px与rem转换问题
Feb 23 #Javascript
解决vue中对象属性改变视图不更新的问题
Feb 23 #Javascript
在Vue组件上动态添加和删除属性方法
Feb 23 #Javascript
vue 路由页面之间实现用手指进行滑动的方法
Feb 23 #Javascript
vue编译打包本地查看index文件的方法
Feb 23 #Javascript
vue 使用Jade模板写html,stylus写css的方法
Feb 23 #Javascript
Angular 向组件传递模板的两种方法
Feb 23 #Javascript
You might like
可以在线执行PHP代码包装修正版
2008/03/15 PHP
FleaPHP的安全设置方法
2008/09/15 PHP
如何利用PHP执行.SQL文件
2013/07/05 PHP
无刷新动态加载数据 滚动条加载适合评论等页面
2013/10/16 PHP
测试php连接mysql是否成功的代码分享
2014/01/24 PHP
十大使用PHP框架的理由
2015/09/26 PHP
PHP实现的进度条效果详解
2016/05/03 PHP
JS两种定义方式的区别、内部原理
2013/11/21 Javascript
js和jquery设置disabled属性为true使按钮失效
2014/08/07 Javascript
jQuery中:file选择器用法实例
2015/01/04 Javascript
jQuery中的基本选择器用法学习教程
2016/04/14 Javascript
JS中使用DOM来控制HTML元素
2016/07/31 Javascript
详解ES6中的let命令
2020/04/05 Javascript
基于Jquery Ajax type的4种类型(详解)
2017/08/02 jQuery
使用javaScript实现鼠标拖拽事件
2020/04/03 Javascript
ES6使用export和import实现模块化的方法
2018/09/10 Javascript
JS实现继承的几种常用方式示例
2019/06/22 Javascript
Vue中import from的来源及省略后缀与加载文件夹问题
2020/02/09 Javascript
用Nodejs实现在终端中炒股的实现
2020/10/18 NodeJs
JavaScript快速调试的两个技巧
2020/11/04 Javascript
[48:20]OpTic vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python 调用HBase的简单实例
2016/12/18 Python
Python对List中的元素排序的方法
2018/04/01 Python
Python3实现监控新型冠状病毒肺炎疫情的示例代码
2020/02/13 Python
Python找出列表中出现次数最多的元素三种方式
2020/02/24 Python
解决jupyter notebook 出现In[*]的问题
2020/04/13 Python
python pymysql链接数据库查询结果转为Dataframe实例
2020/06/05 Python
Python批量修改xml的坐标值全部转为整数的实例代码
2020/11/26 Python
HTML5自定义视频播放器源码
2020/01/06 HTML / CSS
生产部主管岗位职责
2014/01/06 职场文书
学校介绍信范文
2014/01/14 职场文书
保安的辞职报告怎么写
2014/01/20 职场文书
创建绿色社区汇报材料
2014/08/22 职场文书
nginx优化的六点方法
2021/03/31 Servers
Python按顺序遍历并读取文件夹中文件
2022/04/29 Python
浅谈Node的内存泄露问题
2022/05/06 NodeJs