UNPKG

s94-file

Version:

浏览器中,用于文件上传和在线文件选择的可视化插件

337 lines (332 loc) 13.9 kB
(function($){ "use strict"; var __DIR__= $.dirname(module.filename),rem, boxdom, boxid='s94_file'+(new Date()).getTime(), $menu,$tabs,$num,$input_file, setup = {}, dir_stack=[''], mime_map={ 'jpg':'image/jpeg','jpeg':'image/jpeg','png':'image/png','gif':'image/gif','ico':'image/x-icon','webp':'image/webp','bmp':'image/bmp', 'mp4':'video/mp4','avi':'video/avi','wmv':'video/x-ms-wmv', 'mp3':'audio/mp3','aif':'audio/aiff','aiff':'audio/aiff','wav':'audio/wav','wma':'audio/x-ms-wma','m4a':'audio/x-m4a', 'txt':'text/plain','js':'application/javascript,text/javascript','css':'text/css','xml':'text/xml','jsp':'text/html','html':'text/html','htm':'text/html','asp':'text/asp', 'ppt':'application/vnd.ms-powerpoint','pptx':'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'xls':'application/vnd.ms-excel','xlsx':'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'doc':'application/msword','pdf':'application/pdf','docx':'application/vnd.openxmlformats-officedocument.wordprocessingml.document', }, STR = { 'ajax_error': '网络异常,请稍后再试', 'select_error': '最多只能选择一个文件!', 'no_url': 'upload_url和filelist_url至少配置一个!', 'this_dir': '当前路径:/', 'upload': '本地上传', 'online': '在线管理', 'ok': '确定', 'cancel': '取消', 'select': '点击选择文件', }; //工具函数 var tips = $.msg.tips; function ajax(op){ op.global = false; op.type = "post"; $.ajax(op); } function file_type(name){ try{ return name.match(/\.(\w+)$/)[1]; }catch(e){ return ''; } } function is_img(type){ return ['jpg','jpeg','png','gif'].indexOf(type) !== -1; } function img_src(value){ return !/^https?:\/\//.test(value) && setup.host ? '//'+setup.host+value : value; } function file_html(op){ op.type = op.type || file_type(op.url); op.index = op.index || ''; var imgsrc = is_img(op.type) ? img_src(op.url) : __DIR__+'/image/type/'+op.type+'.png'; var html = '<li file '+(op.checked?'class="checked"':'')+' index="'+op.index+'" title="'+op.url+'" file_url="'+op.url+'" >'; html+='<img onerror="'+boxid+'_imger(this)" type="'+op.type+'" src="'+imgsrc+'">'; html+=(op.marsk?'<b></b>':'')+'<i onclick="'+boxid+'_select(this)"><span>'+op.index+'</span></i></li>'; return html; } //请求获取文件列表 function get_manage(dir){ if(!setup.filelist_url) return false; var data = {accept: setup.accept}; if (dir) data['dir'] = dir; ajax({ url: setup.filelist_url, data: data, success: function(res){ get_manage.files = res.data.files; $tabs.eq(1).find('ul li').remove(); var html = '<li dir><span style="font-size: 0.16em;">'+STR['this_dir']+(dir||'')+'</span></li>' if (dir_stack.length > 1) {//是否存在上级目录 html += '<li dir onclick="'+boxid+'_dir(this)" dir_name="../"><span>../</span></li>'; } for(var i=0;i<res.data.dirs.length;i++){ var name = $.trim(res.data.dirs[i],'/').split('/').pop(); html += '<li dir onclick="'+boxid+'_dir(this)" dir_name="'+res.data.dirs[i]+'"><span>'+name+'</span></li>'; } $tabs.eq(1).find('ul>p').before(html); get_manage.index = 0; get_manage.over = false; get_manage.loop(); }, error: function(res){ tips(res.message) } }) } get_manage.loop = function(){ if(get_manage.over) return; var $p = $tabs.eq(1).find('ul>p'); var dty = $p.domOffsetParent()['y']; if(dty > 4*rem) return; var i = get_manage.index || 0; var end = i+5; if(end >= get_manage.files.length){ end = get_manage.files.length; get_manage.over = true; } for (var html=''; i < end; i++) { html += file_html({url: get_manage.files[i]}); } get_manage.index = i; $p.before(html); get_manage.loop(); } function init(){ if(boxdom) return; boxdom = document.createElement('div'); var html=''; html+='<style type="text/css">'; html+='#'+boxid+'{position: fixed;color:#333;left: 0;top: 0;width: 100%;height: 100%;z-index: 999999;background: rgba(0,0,0,.5);display: flex;justify-content: center;align-items: center;}'; html+='#'+boxid+' *{box-sizing:border-box;margin: 0;padding: 0;list-style-type: none;}'; html+='#'+boxid+' span{font-size: 0.2em;line-height:1;}'; html+='#'+boxid+'>dl{display: flex;flex-direction: column;position: relative;width: 6.4em;height: 4.5em;background: #fff;}'; html+='#'+boxid+'>dl>ol{height: 0.6em;padding: 0.1em;display: flex;border-bottom: 0.01em solid #dadada;}'; html+='#'+boxid+'>dl>ol>*{margin: 0 0.05em;flex-grow:1;display:flex;justify-content: center;align-items: center;}'; html+='#'+boxid+'>dl>ol>li{height: 0.4em;cursor:pointer;background:#fff;border:0.01em solid #CFCFCF;border-radius:3px;transition:background .3s;}'; html+='#'+boxid+'>dl>ol>li.checked{color:#fff;background:#00B7EE;border-color:transparent;}'; html+='#'+boxid+'>dl>dd{position:relative;width: 100%;padding: 0.05em;padding-top: 0.05em;overflow: auto;flex: 1 1;}'; html+='#'+boxid+'>dl ul{border:3px dashed #E6E6E6;overflow: auto;width: 100%;height: 100%;display: flex;flex-wrap: wrap;align-content: flex-start;}'; html+='#'+boxid+'>dl ul::-webkit-scrollbar {display: none;}'; html+='#'+boxid+' *[dir]{width: 100%;height: 0.28em;display: flex;align-items: center;padding-left: 0.16em;background: url('+__DIR__+'/image/dir.png) 0.03em 0.05em no-repeat;background-size: auto 0.18em;cursor: pointer;}'; html+='#'+boxid+' *[dir]:first-child{height: 0.2em;padding: 0;background: none;}'; html+='#'+boxid+' *[dir]:nth-child(even){background-color: #fafafa;}'; html+='#'+boxid+' *[file]{width: 1.2em;height: 1.2em;position: relative;margin: 0.01em;border: 0.01em solid #ccc;overflow: hidden;display: flex;justify-content: center;align-items: center;}'; html+='#'+boxid+' *[file] img{width: 1.2em;height: 1.2em;object-fit: cover;}'; html+='#'+boxid+' *[file] b{position: absolute;z-index: 2;right: 0;top: 0;height: 100%;width: 100%;background: rgba(0,0,0,.7);transition: width .3s;}'; html+='#'+boxid+' *[file]>i{width: 0.25em;height: 0.25em;position: absolute;top: 0.05em;right: 0.05em;border-radius: 50%;border: 0.02em solid #fff; color: #fff;background: rgba(0,0,0,.3);font-style: normal;display: flex;justify-content: center;align-items: center;cursor: pointer;}'; html+='#'+boxid+' *[file]>i>span{display: none;font-size: 0.16em;}'; html+='#'+boxid+' *[file].checked>i{border: none;background: #00B7EE;}'; html+='#'+boxid+' *[file].checked>i>span{display: block;}'; html+='</style>'; html+='<dl><input id="'+boxid+'-file" multiple="multiple" type="file" style="display: none;">'; html+=' <ol>'; html+=' <li tab="0" class="checked"><span>'+STR['upload']+'</span></li>'; html+=' <li tab="1"><span>'+STR['online']+'</span></li>'; html+=' <p style="width: 0.5em;"></p>'; html+=' <li><span>'+STR['cancel']+'</span></li>'; html+=' <li class="checked"><span>'+STR['ok']+'(<font>0</font>)</span></li>'; html+=' </ol>'; html+=' <dd style="display: block;">'; html+=' <ul><label file for="'+boxid+'-file"><img src="'+__DIR__+'/image/add.png" title="'+STR['select']+'" /></label></ul>'; html+=' </dd>'; html+=' <dd style="display: none;">'; html+=' <ul><p style="width: 100%;"></p></ul>'; html+=' </dd>'; html+='</dl>'; boxdom.id = boxid; boxdom.style.display = 'none'; boxdom.innerHTML = html; $('body').append(boxdom); $menu = $('#'+boxid+'>dl>ol>li[tab]'); $tabs = $('#'+boxid+'>dl>dd'); $num = $('#'+boxid+' ol font'); $input_file = $('#'+boxid+'-file'); //事件绑定 $menu.on('click',function(){ var $this = $(this); if($this.hasClass('checked')) return; $menu.removeClass('checked'); $this.addClass('checked'); var tab = $this.attr('tab'); $tabs.hide().eq($this.attr('tab')).show(); }) $('#'+boxid+'>dl>ol>li').eq(2).on('click',function(){ $(boxdom).hide(); if (setup.cancel && typeof(setup.cancel) === 'string') { (new Function(setup.cancel)).call(setup.thisArg); } else if (typeof(setup.cancel) === 'function') { setup.cancel.call(setup.thisArg); } }) $('#'+boxid+'>dl>ol>li').eq(3).on('click',function(){ var result = {},files = []; $('#'+boxid+' ul>li.checked').each(function(){ result[$(this).attr('index')] = $(this).attr('file_url'); }) for (var i in result) { files.push(result[i]) } $(boxdom).hide(); if (setup.ok && typeof(setup.ok) === 'string') { (new Function('files', setup.ok)).call(setup.thisArg, files); } else if (typeof(setup.ok) === 'function') { setup.ok.call(setup.thisArg, files); } }) //上传文件 $input_file.on('change',function(){ var fs = this.files; if ( fs.length > setup.max_file ) return tips('最多上传'+setup.max_file+'个文件'); $('#'+boxid+' ul>li.checked').removeAttr('index').removeClass('checked'); var $upload_btn = $tabs.eq(0).find('ul>label'); $upload_btn.hide(); var num = 0, over_num=0; $.each(this.files, function(f) { var thisNum = ++num; var op = { url: '', type: file_type(f.name), checked: true, index: thisNum, marsk: true } if(!op.type) $.each(mime_map, function(v,k){ if(f.type == v) { op.type = k; return false; } }) if(is_img(op.type)) op.url = window.URL.createObjectURL(f); $upload_btn.before( file_html(op) ); var $li = $tabs.eq(0).find('ul>li[index="'+thisNum+'"]'); upload(f, 0); function oncomplete(){ if(num <= ++over_num) { $input_file.val(''); $upload_btn.show(); } } function onerror(){ $li.remove(); oncomplete(); } function upload(file, start){ var len = setup.max_size;// 单次上传最多size,超过的会执行断点续传 var over = false; if(file.size - start < len){ len = file.size - start; over = true; } if(len <= 0) return $li.remove(); var fd = new FormData(); var f = (start==0&&over) ? file : new File([file.slice(start, start + len)], file.name, {type: file.type}); fd.append('file', f); fd.append('filesize', file.size); ajax({ url:setup.upload_url, data: fd, success: function(res){ if(!over){ var w = (1 - (start+len)/file.size)*100 + '%'; $li.find('b').css('width',w); return upload(file, start+len); } $li.attr('title', res.data).attr('file_url', res.data).find('b').css('width','100%').hide(200); if(is_img(op.type)) $li.find('img').attr('src', img_src(res.data)); oncomplete(); }, progress: function(pro){ var percent = pro.loaded/pro.total; var w = (1 - start/file.size - (len/file.size)*percent)*100 + '%'; $li.find('b').css('width',w); }, error: function(res){ tips(res.message); onerror(); } }) } }); $num.text(num); }) $tabs.eq(1).find('ul').on('scroll',function(){ get_manage.loop(); }) //全局功能函数 window[boxid+'_imger'] = function(_this){ $(_this).parent().append('<p style="color: #fff;position: absolute;left: 0.13em;top: 0.17em;width: 0.47em;height: 0.2em;display: flex;justify-content: center;align-items: center;"><span>'+_this.getAttribute('type')+'</span></p>'); _this.src = __DIR__+'/image/type/__root.png'; } window[boxid+'_preview'] = function(_this){ window.open(_this.parentNode.getAttribute('file_url'),'_blank'); } window[boxid+'_select'] = function(_this){ var $file_li = $(_this.parentNode); var $checked = $('#'+boxid+' ul>li.checked'); if ($file_li.hasClass('checked')) { var cache_i,this_i = $file_li.attr('index'); $checked.each(function(){ cache_i = $(this).attr('index'); if(cache_i > this_i){ $(this).attr('index', (cache_i-1)).find('i>span').text(cache_i-1); } }) $file_li.removeClass('checked').removeAttr('index').find('i>span').text(''); $num.text($checked.length-1); } else{ if ($checked.length >= setup.max_file) return tips('最多选择'+setup.max_file+'个文件'); $file_li.addClass('checked').attr('index', $checked.length+1).find('i>span').text($checked.length+1); $num.text($checked.length+1); } } window[boxid+'_dir'] = function(_this){ var dir_name = $(_this).attr('dir_name'); if (dir_name=='../' && dir_stack.length>1) { dir_stack.pop(); } else{ dir_stack.push(dir_name); } get_manage(dir_stack[dir_stack.length-1]); } } function file(config){ if(!boxdom) init(); rem = $.rem.get(); boxdom.style.fontSize = rem+'px'; //初始化管理器 $menu.removeClass('checked').hide(); $tabs.hide(); $num.text(0); $input_file.removeAttr('accept'); dir_stack=['']; //配置上传设置 setup = $.merge({accept: '', max_file: 1, max_size: 10*1024*1024}, config); if(setup.upload_url) { $menu.eq(0).show().addClass('checked'); $tabs.eq(0).show(); if(setup.filelist_url) $menu.eq(1).show(); }else if(setup.filelist_url){ $menu.eq(1).show().addClass('checked'); $tabs.eq(1).show(); }else{ throw new Error(STR['no_url']); } if (setup.accept) { var accept=[]; setup.accept.split(',').forEach(function(row){ if (row in mime_map) accept.push(mime_map[row]); }) $input_file.attr('accept',accept.join(',')); } setup.name = setup.name || 'file'; $tabs.eq(0).find('ul li').remove(); $tabs.eq(0).find('ul>label').show(); get_manage(); $(boxdom).show(); } module.exports = file; })(require('s94-web'));