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 相关文章推荐
Javascript 读后台cookie代码
Sep 15 Javascript
csdn 博客的css样式 v3
Feb 24 Javascript
javascript 学习笔记(六)浏览器类型及版本信息检测代码
Apr 08 Javascript
仿微博字符限制效果实现代码
Apr 20 Javascript
javascript间隔刷新的简单实例
Nov 14 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
Feb 19 Javascript
jquery自动补齐功能插件flexselect用法示例
Aug 06 Javascript
JS中利用FileReader实现上传图片前本地预览功能
Mar 02 Javascript
koa+jwt实现token验证与刷新功能
May 30 Javascript
javascript 高级语法之继承的基本使用方法示例
Nov 11 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
Apr 26 Javascript
微信小程序仿抖音视频之整屏上下切换功能的实现代码
May 24 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编程中八种常见的文件操作方式
2006/11/19 PHP
php网页后退不再出现过期
2007/03/08 PHP
防止用户利用PHP代码DOS造成用光网络带宽
2011/03/01 PHP
PHP对象转换为数组函数(递归方法)
2012/02/04 PHP
利用phpexcel把excel导入数据库和数据库导出excel实现
2014/01/09 PHP
PHP使用递归方式列出当前目录下所有文件的方法
2015/06/02 PHP
标准版Eclipse搭建PHP环境的详细步骤
2015/11/18 PHP
javascript RadioButtonList获取选中值
2009/04/09 Javascript
JavaScript生成随机字符串的方法
2015/03/19 Javascript
javascript 判断当前浏览器版本并判断ie版本
2017/02/17 Javascript
微信小程序 开发之顶部导航栏实例代码
2017/02/23 Javascript
Vue.js 2.5新特性介绍(推荐)
2017/10/24 Javascript
微信小程序wx.request实现后台数据交互功能分析
2017/11/25 Javascript
Vue.set()实现数据动态响应的方法
2018/02/07 Javascript
vue踩坑记-在项目中安装依赖模块npm install报错
2019/04/02 Javascript
详解Vue.js和layui日期控件冲突问题解决办法
2019/07/25 Javascript
Vue 打包体积优化方案小结
2020/05/20 Javascript
[05:06]DOTA2-DPC中国联赛 正赛 VG vs Magma选手采访
2021/03/11 DOTA
python处理csv数据的方法
2015/03/11 Python
python实现基本进制转换的方法
2015/07/11 Python
python numpy实现rolling滚动案例
2020/06/08 Python
详解Django ORM引发的数据库N+1性能问题
2020/10/12 Python
python按照list中字典的某key去重的示例代码
2020/10/13 Python
Pandas中DataFrame交换列顺序的方法实现
2020/12/14 Python
使用CSS实现弹性视频html5案例实践
2012/12/26 HTML / CSS
马来西亚和新加坡巴士票在线预订:CatchThatBus
2018/11/17 全球购物
美国家庭鞋店:Shoe Sensation
2019/09/27 全球购物
高中毕业生自我鉴定例文
2013/12/29 职场文书
军训 自我鉴定
2014/02/03 职场文书
爱心捐助倡议书
2014/05/19 职场文书
安全标语大全
2014/06/10 职场文书
驾驶员安全责任书范本
2014/07/24 职场文书
大学生年度个人总结
2015/02/15 职场文书
保密法制宣传月活动总结
2015/05/07 职场文书
观后感格式
2015/06/19 职场文书
2016感恩母亲节校园广播稿
2015/12/17 职场文书