Jq /Js 拖动选择文件
必须先引入 Jquery 依赖
1.文件结构
2. HTML
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>拖拽</title> <link rel="stylesheet" type="text/css" href="./css/index.css" /> <script src="./js/jquery-3.5.1.min.js"></script> <script src="./js/index.js"></script> </head> <body> <!-- 触发按钮 --> <button type="button" id="clickBtn" class="clickBtn">点击选择</button> <!-- 拖拽盒子 --> <div id="select_file_div"class="select_file_div"> <div id="drag_file_div"class="drag_file_div"contenteditable="true"> <p class="drag_file_div_p"contenteditable="false">请选择或拖拽文件至此区域</p> </div> <div id="drag_file_control"class="drag_file_control noSelect"> <p>暂未选择文件</p><span>按住任意拖动</span> <div id="drag_file_cancel"class="drag_file_cancel">完成</div><a href="javascript:void(0);"id="select_file_a"class="select_file_a"><input type="file"multiple="true"id="select_file_addFile"class="select_file_addFile">手动选择</a> </div> </div> </body> </html>
3. CSS
*{margin:0;padding:0;box-sizing:border-box}.clickBtn{width:148px;height:48px;letter-spacing:4px;font-size:16px;margin:16px 0 0 16px}.tip{width:auto;min-width:168px;height:60px;position:fixed;left:44%;z-index:199;padding:0 8px 0 8px;line-height:60px;text-align:center;font-size:18px;border-radius:4px;box-shadow:#393D49 2px 2px 8px;background-color:#1E9FFF;color:#ffffff;animation:tip 0.3s;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}@keyframes tip{from{top:0px}to{top:80px}}@-webkit-keyframes tip{from{top:0px}to{top:80px}}.tipKill{animation:tipKill 1s;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}@keyframes tipKill{from{top:80px}to{background-color:rgba(0,0,0,0);box-shadow:rgba(0,0,0,0) 2px 2px 8px;color:rgba(0,0,0,0);top:0px}}@-webkit-keyframes tipKill{from{top:80px}to{background-color:rgba(0,0,0,0);box-shadow:rgba(0,0,0,0) 2px 2px 8px;color:rgba(0,0,0,0);top:0px}}.noSelect{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.select_file_div{display:none;width:650px;position:fixed;top:20%;left:32%;z-index:101}.drag_file_div{width:100%;height:340px;padding:3px;background:url("../img/b2.jpg");background-size:100%;border:1px solid #4b4b4b;box-shadow:inset 0 1px 1px #d6d6d6;outline:medium;font-size:14px}.drag_file_div>p{position:absolute;width:240px;height:50px;text-align:center;left:0;top:0;right:0;bottom:0;margin:auto;border:1px dashed #ddd;font-size:1em;color:#999;display:block;line-height:50px}.drag_file_selectfile{width:98%;height:38px;margin:8px 1%;line-height:38px;color:#bfbfbf;background-color:#393D49;box-shadow:1px 1px 1px #ffffff}.drag_file_selectfile:hover{color:#eeeeee;box-shadow:2px 2px 4px #ffffff}.drag_file_selectfile>div{float:left}.drag_file_selectfile .select_filename{width:388px;height:38px;margin-left:10px}.drag_file_selectfile .select_filesize{width:168px;margin-left:10px}.drag_file_selectfile .select_file_clear{display:block;width:20px;height:20px;margin:9px;background:url("../img/delete1.png");background-size:100%;cursor:pointer}.drag_file_selectfile .select_file_clear:hover{background:url("../img/delete2.png");background-size:100%}.drag_file_selectfile>div>span:nth-child(1){font-weight:700;margin:0 6px 0 0}.drag_file_control{width:650px;margin:0 auto;height:45px;line-height:45px;background:#393D49;border-width:0 1px 1px 1px;border-style:solid;border-color:#747474;cursor:pointer}.drag_file_control .select_file_a{position:relative;width:92px;height:34px;line-height:34px;text-decoration:none;color:#ffffff;font-size:14px;letter-spacing:2px;cursor:pointer;background:#89a3b3;border-radius:3px;overflow:hidden;text-align:center;float:right;margin:5px 8px 5px}.drag_file_control .select_file_a>input{position:absolute;width:92px;height:34px;right:0;top:0;opacity:0;cursor:pointer}.select_file_addFile{display:block;margin:0 auto;text-align:center;font-size:14px;cursor:pointer}.drag_file_control>p{width:158px;color:#d9d9d9;float:left;font-size:14px;padding-left:20px}.drag_file_control>span{margin:0 0 0 24px;color:#666;font-size:14px}.dragOver{box-shadow:inset 1px 1px 2px rgba(0,0,0,.5) !important}.drag_file_cancel{width:92px;height:34px;background:#1c8fe5;color:#eeeeee;font-size:14px;letter-spacing:4px;border-radius:3px;display:block;line-height:34px;text-align:center;cursor:pointer;float:right;margin:5px 8px 5px}.select_file_a:hover,.drag_file_cancel:hover{opacity:0.6}
4. JS
var selectFileArr = new FormData(); // 选中文件 var selectFileArrKey = []; // 选中文件名集合 var selectFileSizeSum = 0; // 选中文件总大小 var maxFileNum = 1; // 选择文件数量上限 var maxFileSize = 100; // 选择文件大小上限(单位Mb) var sheetErrorData = {}; // 导入失败数据 var canFileType = ['.xlsx']; // 允许的文件类型 var dragFileDiv = null; // 显示对象_主体盒子 var dragFileTip = null; // 显示对象_提示内容 var errTip = {'background-color': '#ff6528', 'color': '#eeeeee', 'font-weight': '700'}; $(function() { // 拖拽移动 dragMove('#select_file_div', false); // 点击选择文件 $('#clickBtn').click(function() { var parameter = { maxFileNum: 7, maxFileSize: 100 } dragSelectFileLoad(parameter); // 加载 }); }); /** * 加载函数 * @param parameter JSON参数对象 */ function dragSelectFileLoad(parameter) { $('body')[0].contentEditable = false; // 规定元素内容是否可编辑 $('#select_file_div').show(); // 显示盒子 maxFileNum = parameter.maxFileNum || 1; // 最多可选取文件数 maxFileSize = parameter.maxFileSize || 1; // 选择文件大小上限(单位Mb) // 显示对象 dragFileDiv = $('#drag_file_div')[0]; dragFileTip = $('.drag_file_div_p'); // 鼠标拖入时 dragFileDiv.ondragenter = function(ev) { dragFile.evStop(ev); dragFileTip.text('请释放鼠标'); $(this).addClass('dragOver'); } // 移出 dragFileDiv.ondragleave = function(ev) { dragFile.evStop(ev); dragFileTip.text('请添加或拖拽文件至此区域'); $(this).removeClass('dragOver'); } // 释放元素 dragFileDiv.ondrop = function(ev) { dragFile.evStop(ev); this.setAttribute('contenteditable', 'false'); // 不可再拖动 dragFile.readFile(ev); } // 选择文件后 $('#select_file_addFile').change(function() { dragFile.addCheck($('#select_file_addFile')[0].files[0]); // 文件校验 }); // 取消按钮 $('#drag_file_cancel').click(function() { $('#select_file_div').hide(); }); } /** * 拖拽文件操作对象 */ var dragFile = { // 读取拖拽文件 readFile: function(ev) { var File = ev.dataTransfer.files; for (var i = 0; i < File.length; i++) { dragFile.addCheck(File[i]); } }, // 文件格式验证 addCheck: function(file) { var fnLast = file.name.substr(file.name.lastIndexOf('.')); if (!isNull(file.name) && canFileType.indexOf(fnLast) != -1) { // 文件类型校验 // console.log(selectFileArrKey.length, maxFileNum); if (selectFileArrKey.length < maxFileNum && maxFileNum > 0) { // 文件数量限制 if (!selectFileArr.has(file.name)) { // 文件名未重复 var fileSize = file.size / 1048576; if (selectFileSizeSum + file.size < maxFileSize * 1048576) { // 总文件大小限制 selectFileSizeSum += file.size; // 记录文件总大小 dragFile.addFile(file, fileSize.toFixed(2)); // 添加文件 } else { tip('文件大小不能超过 ' + maxFileSize + ' MB', 1200, errTip); } } else { tip('文件名重复', 1200, errTip); } } else { tip('最多可选择 ' + maxFileNum + ' 个文件', 1200, errTip); } } else { tip('不支持的文件格式', 1200, errTip); } }, // 列表显示 addFile: function(file, fileSize) { var fileName = file.name; // 文件名 var showFileName = file.name; // 显示文件名 var tpFl = fileName.substr(fileName.lastIndexOf('.')); // 后缀 if (fileName.length > 16 + tpFl.length) { // 超过长度则截取 showFileName = fileName.substring(0, 16) + '……' + tpFl; } selectFileArr.append(file.name, file); // 添加文件 selectFileArrKey.push(file.name); // 记录文件名 dragFileTip.hide(); // 隐藏提示文字 updateShowFileName(); // 更新显示 var str = "<div class=\"drag_file_selectfile\" contenteditable=\"false\">" + "<div class=\"select_filename\"><span>文件名</span>" + showFileName + "</div>" + "<div class=\"select_filesize\"><span>文件大小:</span>" + fileSize + 'MB' + "</div>" + "<div class='select_file_clear' onclick=\"dragFile.removeFile('" + fileName + "', this)\"></div></div>"; $('#drag_file_div').append(str); }, // 移除文件 removeFile: function(fileName, that) { fileName = fileName.trim(); if (selectFileArr.has(fileName)) { selectFileArr.delete(fileName); // 移除数据 $(that).parent().remove(); // 找到父元素并删除 // 去除删除元素Key var tpSfakArr = []; for (let k in selectFileArrKey) { if (selectFileArrKey[k] != fileName) tpSfakArr.push(selectFileArrKey[k]); } selectFileArrKey = tpSfakArr; updateShowFileName(); // 更新显示 tip('文件 【 ' + fileName + ' 】 移除成功', 2000, {}); } if (selectFileArrKey.length <= 0) { $('.drag_file_div_p').show(); // 显示提示文字 } }, // Url事件截停 evStop: function(e) { var ev = e || window.event; ev.preventDefault(); ev.stopPropagation(); // Fiefox兼容 }, // 重置 reset: function() { selectFileArr = new FormData(); // 选中文件数 selectFileArrKey = []; // 选中文件数 dragFileDiv = null; // 显示对象_主体盒子 dragFileTip = null; // 显示对象_提示内容 $('#select_file_addFile').reset(); } } /** * 更新文件名显示 */ function updateShowFileName() { if (selectFileArrKey.length > 0) { // var fileSpanFileName = selectFileArrKey.join(' / '); // $('#file_span').text(fileSpanFileName.length <= 24 ? fileSpanFileName : fileSpanFileName.substring(0, 24) + ' ……'); $('#drag_file_control>p').text('选择了' + selectFileArrKey.length + '个文件'); // 添加显示 } else { // $('#file_span').text('暂未选择文件'); $('#drag_file_control>p').text('暂未选择文件'); // 添加显示 $('#drag_file_div>div').remove(); $('.drag_file_div_p').show(); // 显示提示文字 } } /** * 拖拽移动 * @param obj 目标对象 / #id / .class * @param moveOut 是否可以移出边界 */ function dragMove(dom, moveOut) { var obj = $(dom); moveOut = moveOut || false; obj.bind('mousedown', start); var deltaX = 0, deltaY = 0; function start(e) { var ol = obj.offset().left; var ot = obj.offset().top; deltaX = e.pageX - ol; deltaY = e.pageY - ot; $(document).bind({ 'mousemove': move, 'mouseup': stop }); return false; } function move(e) { var tpX = 0, tpY = 0; if ((e.pageX - deltaX > 0 && e.pageY - deltaY > 0) || moveOut) { tpX = e.pageX - deltaX; tpY = e.pageY - deltaY; } else if (e.pageX - deltaX <= 0 && e.pageY - deltaY > 0) { tpX = 0; tpY = e.pageY - deltaY; } else if (e.pageX - deltaX > 0 && e.pageY - deltaY <= 0) { tpX = e.pageX - deltaX; tpY = 0; } obj.css({ "left": (tpX), "top": (tpY) }); return false; } function stop() { $(document).unbind({ 'mousemove': move, 'mouseup': stop }); } } /** * 提示 * @param {Object} msg * @param {Object} t * @param {Object} style 自定义样式,必须是json格式 */ function tip(msg, t, style) { var tipId = 'tip' + (new Date().getTime()); var styleto = ''; if (!isNull(style)) { for (var s in style) { styleto += s + ': ' + style[s] + ';'; } } $('body').append("<div id='" + tipId + "' class='tip' style='" + styleto + "'>" + msg + "</div>"); setTimeout(function() { $('#' + tipId).addClass('tipKill'); setTimeout(function() { $('#' + tipId).remove(); }, t); }, t); } /** * 空判断 * @param {Object} obj */ function isNull(obj) { return obj == null || obj == undefined || obj == '' || obj == NaN || ('' + obj) == '{}'; }
5.效果图
基于作者 “三宝鸭” 代码重构,实现了高度动态化
理了一下逻辑和注释,增强了兼容性,大家仍可以 diy 成更适合自己的模块
参考链接:原生 JS 写拖拽文件上传_三宝鸭的博客-CSDN博客
转载请附上本文链接