前端页面文件拖拽上传模块js代码示例


Posted in Javascript onMay 19, 2017

最近给卫生局做一个表格上传/可视化系统,算是小有成果。今天把项目中的文件拖拽上传模块分离出来,做了一个独立的小demo,并把相关代码打包上传到了我的github中,为了其他学习者和开发者提供拙见。

gitHub地址:https://github.com/codeplay2015/dragToUpload

由于代码中我的注释很详尽,所以具体逻辑实现及不介绍了,大家直接看代码及能明白。现在简单列一个功能清单和一些用到的知识点清单:

  • 模态框
  • 文件的批量上传
  • 使用formData API 封装数据 并通过ajax方法提交
  • 读取拖放文件,ondrop事件 dataTransfer对象
  • 清空所有文件

知识点:

  • 单例模式:构建一个单例模式的formData容器
  • 事件冒泡,事件委托:动态添加删除单个文件的方法
  • css各种布局,BFC
  • CSS 伪类 link vistied hover active
  • html 离线操作文档:创建fragment 离线操作,提高性能,减少浏览器的重绘和回流
  • 原型链,原型方法:为formData对象添加一个删除所有文件的方法
  • CSS伪对象,结合after伪对象画一个‘X'号,放在模态框右上角表示退出按钮

截图:

整体界面

前端页面文件拖拽上传模块js代码示例

点击‘拖拽上传'按钮

前端页面文件拖拽上传模块js代码示例

拖拽文件到虚线框,文件拖入会边框变红提示

前端页面文件拖拽上传模块js代码示例

上传成功,弹出提示

前端页面文件拖拽上传模块js代码示例

代码:

1. html:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
 <link rel="stylesheet" href="demo.css" rel="external nofollow" >
</head>
<body>
 <!--遮罩-->
 <div class="overlay"></div>
 <!--模态框-->
 <div id="modal" class="dropbox">
  <div class="items-container">
   <div id="close" style="cursor:pointer;float: right;width:20px">
    <span class="css-close"></span>
   </div>
   <div>
    <p class="head"><b>拖拽文件至此</b></p>
    <div class="content" id="content">
     <table class="table">
      <tbody class="tbody"></tbody>
     </table>
    </div>
    <div class="footer">
     <button class="btn" onclick="upload()">开始上传</button>
    </div>
    <a href='#' onclick='clearAll()' style='position:absolute;bottom:10px;right:30px;'>清空所有</a>
   </div>
  </div>
 </div>
 <!--页面内容-->
 <div style="margin-top:40vh;text-align: center;">
  <p>拖拽上传演示模板。点击下方按钮,弹出模态框</p>
  <button class="btn" onclick="showModal()">点击上传</button>
 </div>
 <!--嵌入脚本-->
 <script src="jquery-1.10.2.js" type="text/javascript"></script>
 <script src="demo.js" type="text/javascript"></script>
</body>
</html>

CSS

.overlay{
 z-index: 99;
 position:fixed;
 display: none;
 top:0;
 left:0;
 width: 100%;
 height: 100%;
 background-color: #333;
 opacity:0.5;
}
.dropbox{
 z-index: 100;
 display: none;
 position: fixed;
 width:500px;
 height:520px;
 margin:auto;
 top:0;
 right:0;
 bottom: 0;
 left:0;
 background-color: #fff;
 border-radius:6px;
 transition-duration: 0.9s;
 -webkit-transition-duration: 0.9s;
 overflow:hidden;
 text-align: center;
}
.items-container{
 padding: 10px;
}
.content{
 border: 3px dashed gray;
 border-radius: 10px;
 margin: 10px 20px;
 height:400px;
 overflow: auto;
 padding:2px 8px;
}

.head{
 margin:0px;
 font-size:30px;
 color:#aaa;
}
.footer{
 margin:5px auto
}
.btn{
 border-radius: 20px;
 box-sizing: border-box;
 border-width: 2px;
 background-color: transparent;
 font-size: 14px;
 font-weight: 500;
 padding: 7px 18px
}
/*画一个叉号,表示推出界面*/
.css-close{display:inline-block; width:15px; height:2px; background:#000; font-size:0; line-height:0;vertical-align:middle;-webkit-transform: rotate(45deg);}
.css-close:after { content:'.'; display:block; width:15px; height:2px; background:#000;-webkit-transform: rotate(90deg);}

/*表格样式*/
.table{
 width:100%;
 border-collapse: collapse;
}
#content tr:first-child td{
 border-top-width: 0px;
}
#content tr td:last-child{
 cursor: pointer;
 color: red;
}
#content tr td{
 padding: 8px;
 white-space: nowrap;
 overflow: hidden;
 text-overflow:ellipsis;
 border-top:1px solid #9A9A9A;
}
#content tr:hover{
 background-color: #d5d5d5;
}
#content tr:active{
 background-color: #9A9A9A;
}
a:link{
 color:blue;
}
a:visited{
 color:blue;
}
a:hover{
 color:blue;
}
a:active{
 color:red;
}

js代码:

function showModal() { //打开上传框
 var modal = document.getElementById('modal');
 var overlay = document.getElementsByClassName('overlay')[0];
 overlay.style.display = 'block';
 modal.style.display = 'block';
}
function closeModal() { //关闭上传框
 var modal = document.getElementById('modal');
 var overlay = document.getElementsByClassName('overlay')[0];
 overlay.style.display = 'none';
 modal.style.display = 'none';
}
//用DOM2级方法为右上角的叉号和黑色遮罩层添加事件:点击后关闭上传框
document.getElementsByClassName('overlay')[0].addEventListener('click', closeModal, false);
document.getElementById('close').addEventListener('click', closeModal, false);

//利用html5 FormData() API,创建一个接收文件的对象,因为可以多次拖拽,这里采用单例模式创建对象Dragfiles
var Dragfiles=(function (){
 var instance;
 return function(){
  if(!instance){
   instance = new FormData();
  }
  return instance;
 }
}());
//为Dragfiles添加一个清空所有文件的方法
FormData.prototype.deleteAll=function () {
 var _this=this;
 this.forEach(function(value,key){
  _this.delete(key);
 })
}

//添加拖拽事件
var dz = document.getElementById('content');
dz.ondragover = function (ev) {
 //阻止浏览器默认打开文件的操作
 ev.preventDefault();
 //拖入文件后边框颜色变红
 this.style.borderColor = 'red';
}

dz.ondragleave = function () {
 //恢复边框颜色
 this.style.borderColor = 'gray';
}
dz.ondrop = function (ev) {
 //恢复边框颜色
 this.style.borderColor = 'gray';
 //阻止浏览器默认打开文件的操作
 ev.preventDefault();
 var files = ev.dataTransfer.files;
 var len=files.length,
  i=0;
 var frag=document.createDocumentFragment(); //为了减少js修改dom树的频度,先创建一个fragment,然后在fragment里操作
 var tr,time,size;
 var newForm=Dragfiles(); //获取单例
 var it=newForm.entries(); //创建一个迭代器,测试用
 while(i<len){
  tr=document.createElement('tr');
  //获取文件大小
  size=Math.round(files[i].size * 100 / 1024) / 100 + 'KB';
  //获取格式化的修改时间
  time = files[i].lastModifiedDate.toLocaleDateString() + ' '+files[i].lastModifiedDate.toTimeString().split(' ')[0];
  tr.innerHTML='<td>'+files[i].name+'</td><td>'+time+'</td><td>'+size+'</td><td>删除</td>';
  console.log(size+' '+time);
  frag.appendChild(tr);
  //添加文件到newForm
  newForm.append(files[i].name,files[i]);
  //console.log(it.next());
  i++;
 }
 this.childNodes[1].childNodes[1].appendChild(frag);
 //为什么是‘1'?文档里几乎每一样东西都是一个节点,甚至连空格和换行符都会被解释成节点。而且都包含在childNodes属性所返回的数组中.不同于jade模板
}
function blink()
{
 document.getElementById('content').style.borderColor = 'gray';
}

//ajax上传文件
function upload(){
 if(document.getElementsByTagName('tbody')[0].hasChildNodes()==false){
  document.getElementById('content').style.borderColor = 'red';
  setTimeout(blink,200);
  return false;
 }
 var data=Dragfiles(); //获取formData
 $.ajax({
  url: 'upload',
  type: 'POST',
  data: data,
  async: true,
  cache: false,
  contentType: false,
  processData: false,
  success: function (data) {
   alert('succeed!') //可以替换为自己的方法
   closeModal();
   data.deleteAll(); //清空formData
   $('.tbody').empty(); //清空列表
  },
  error: function (returndata) {
   alert('failed!') //可以替换为自己的方法
  }
 });
}
// 用事件委托的方法为‘删除'添加点击事件,使用jquery中的on方法
$(".tbody").on('click','tr td:last-child',function(){
 //删除拖拽框已有的文件
 var temp=Dragfiles();
 var key=$(this).prev().prev().prev().text();
 console.log(key);
 temp.delete(key);
 $(this).parent().remove();
});
//清空所有内容
function clearAll(){
 if(document.getElementsByTagName('tbody')[0].hasChildNodes()==false){
  document.getElementById('content').style.borderColor = 'red';
  setTimeout(blink,300);
  return false;
 }
 var data=Dragfiles(); 
 data.deleteAll(); //清空formData
 //$('.tbody').empty(); 等同于以下方法
 document.getElementsByTagName('tbody')[0].innerHTML='';
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
如果文字过长,则将过长的部分变成省略号显示
Jun 26 Javascript
JavaScript触发器详解
Mar 10 Javascript
Uglifyjs(JS代码优化工具)入门 安装使用
Apr 13 Javascript
json原理分析及实例介绍
Nov 29 Javascript
offsetHeight在OnLoad中获取为0的现象
Jul 22 Javascript
推荐9款炫酷的基于jquery的页面特效
Dec 07 Javascript
jQuery插件pagination实现分页特效
Apr 12 Javascript
使用AngularJS编写较为优美的JavaScript代码指南
Jun 19 Javascript
老生常谈JavaScript 正则表达式语法
Aug 20 Javascript
基于JQuery的购物车添加删除以及结算功能示例
Mar 08 Javascript
Vue 中对图片地址进行拼接的方法
Sep 03 Javascript
微信小程序实现注册登录功能(表单校验、错误提示)
Dec 10 Javascript
jQuery操作之效果详解
May 19 #jQuery
AngularJS中的promise用法分析
May 19 #Javascript
几种响应式文字详解
May 19 #Javascript
关于Bootstrap按钮组件消除黄框的方法
May 19 #Javascript
vue.js动态数据绑定学习笔记
May 19 #Javascript
Node.JS利用PhantomJs抓取网页入门教程
May 19 #Javascript
详解如何使用vue-cli脚手架搭建Vue.js项目
May 19 #Javascript
You might like
做一个有下拉功能的留言版
2006/10/09 PHP
我的论坛源代码(十)
2006/10/09 PHP
Zend Framework实现留言本分页功能(附demo源码下载)
2016/03/22 PHP
iOS+PHP注册登录系统 PHP部分(上)
2016/12/26 PHP
javascript中IE浏览器不支持NEW DATE()带参数的解决方法
2012/03/01 Javascript
js与jQuery 获取父窗、子窗的iframe
2013/12/20 Javascript
谈谈jQuery Ajax用法详解
2015/11/27 Javascript
在 Node.js 中使用 async 函数的方法
2017/11/17 Javascript
最实用的JS数组函数整理
2017/12/05 Javascript
10行原生JS实现文字无缝滚动(超简单)
2018/01/02 Javascript
Node.js静态服务器的实现方法
2018/02/28 Javascript
NodeJS父进程与子进程资源共享原理与实现方法
2018/03/16 NodeJs
微信小程序视图容器(swiper)组件创建轮播图
2020/06/19 Javascript
Angular 实现输入框中显示文章标签的实例代码
2018/11/07 Javascript
Vue 进阶之路(三)
2019/04/18 Javascript
layui 实现table翻页滚动条位置保持不变的例子
2019/09/05 Javascript
在LayUI图片上传中,解决由跨域问题引起的请求接口错误的方法
2019/09/24 Javascript
解决vue-cli 打包后自定义动画未执行的问题
2019/11/12 Javascript
功能完善的小程序日历组件的实现
2020/03/31 Javascript
[34:47]完美世界DOTA2联赛PWL S2 Magma vs LBZS 第一场 11.18
2020/11/18 DOTA
详解在Python中处理异常的教程
2015/05/24 Python
学习python的前途 python挣钱
2019/02/27 Python
Python 函数返回值的示例代码
2019/03/11 Python
python时间序列按频率生成日期的方法
2019/05/14 Python
Python调用C语言的实现
2019/07/26 Python
Pytorch技巧:DataLoader的collate_fn参数使用详解
2020/01/08 Python
python爬取代理IP并进行有效的IP测试实现
2020/10/09 Python
Parfumdreams芬兰:购买香水和化妆品
2021/02/13 全球购物
将"引用"作为函数参数有哪些特点
2013/04/05 面试题
医学专业五年以上个人求职信
2013/12/03 职场文书
影视制作岗位职责
2013/12/04 职场文书
评析教师个人的自我评价
2014/02/19 职场文书
大学新闻系自荐书
2014/05/31 职场文书
中班下学期幼儿评语
2014/12/30 职场文书
2015个人年度工作总结范文
2015/05/28 职场文书
七年级思品教学反思
2016/02/20 职场文书