@ -1,10 +1,3 @@
< template >
< label : class = "{'file-uploads': true, 'file-uploads-html5': $mode == 'html5', 'file-uploads-html4': $mode == 'html4'}" >
< span > { { title } } < / span >
< input -file > < / i n p u t - f i l e >
< / label >
< / template >
< style >
. file - uploads {
overflow : hidden ;
@ -42,7 +35,12 @@
< / style >
< script >
import InputFile from './InputFile.vue' ;
export default {
components : {
InputFile ,
} ,
props : {
title : {
type : String ,
@ -81,58 +79,75 @@ export default {
type : Object ,
default : ( ) => { } ,
} ,
} ,
components : {
inputFile : {
template : '<input type="file" :name="$parent.name" :id="$parent.id||$parent.name" :accept="$parent.accept" @change="change" :multiple="$parent.multiple && $parent.$mode == \'html5\'">' ,
methods : {
change ( e ) {
this . $parent . _addFileUploads ( e . target ) ;
this . $destroy ( ) ;
headers : {
type : Object ,
default : ( ) => { } ,
} ,
data : {
type : Object ,
default : ( ) => { } ,
} ,
drop : {
type : Boolean ,
default : false ,
} ,
files : {
type : Array ,
default : ( ) => [ ] ,
} ,
} ,
data ( ) {
return {
files : [ ] ,
mode: 'html5' ,
active : false ,
uploaded : true ,
dropActive : false ,
dropElement : false ,
request : {
data : { } ,
headers : { } ,
} ,
}
} ,
ready ( ) {
this . _drop ( this . drop ) ;
} ,
init ( ) {
/ / 挂 在 后
mounted ( ) {
var input = document . createElement ( 'input' ) ;
input . type = 'file' ;
if ( window . FormData && input . files ) {
this . $ mode = 'html5' ;
this . mode = 'html5' ;
} else {
this . $ mode = 'html4' ;
this . mode = 'html4' ;
}
this . _index = 0 ;
this . _files = [ ] ;
this . _dropActive = 0 ;
this . _files = { } ;
this . _drop ( this . drop )
this . $nextTick ( ( ) => {
this . _drop ( this . drop )
} )
} ,
/ / 销 毁 前
beforeDestroy ( ) {
this . active = false ;
this . files = [ ] ;
} ,
render ( h ) {
return (
< label class = { {
'file-uploads' : true ,
'file-uploads-html5' : this . mode == 'html5' ,
'file-uploads-html4' : this . mode == 'html4'
} } >
< span > { this . title } < / span >
< input -file > < / i n p u t - f i l e >
< / label >
)
} ,
watch : {
drop ( value ) {
this . _drop ( value ) ;
@ -140,36 +155,38 @@ export default {
files ( files ) {
var ids = [ ] ;
for ( var i = 0 ; i < files . length ; i ++ ) {
var file = files [ i ] ;
if ( ! file . err n o && ! file . success ) {
let file = files [ i ] ;
if ( ! file . err or && ! file . success ) {
this . uploaded = false ;
}
ids . push ( file . id ) ;
}
for ( var id in this . _files ) {
if ( ids . indexOf ( id ) != - 1 ) {
continue ;
}
let file = this . _files ;
var file = this . _files [ id ] . _file ;
/ / 已 移 除 的 记 录
file . removed = true ;
var xhr = this . _files [ id ] . xhr ;
/ / x h r a b o r t
var xhr = file . xhr ;
if ( xhr ) {
try {
xhr . abort ( ) ;
xhr . timeout = 1 ;
} catch ( e ) {
}
}
var iframe = this . _files [ id ] . iframe ;
if ( iframe ) {
iframe . onabort ( { type : 'abort' } ) ;
/ / i f r a m e a b o r t
if ( file . iframe ) {
file . iframe . onabort ( { type : 'abort' } ) ;
}
delete this . _files [ id ] ;
this . _uploadEvents ( 'remove FileUpload ', file ) ;
this . _uploadEvents ( 'remove ', file ) ;
}
this . _index = 0 ;
} ,
@ -194,14 +211,51 @@ export default {
}
} ,
addFileUpload ( file ) {
this . uploaded = false ;
var defaultFile = {
size : - 1 ,
name : 'Filename' ,
progress : '0.00' ,
speed : 0 ,
active : false ,
error : '' ,
success : false ,
putAction : this . putAction ,
postAction : this . postAction ,
timeout : this . timeout ,
data : Object . assign ( { } , this . data ) ,
headers : Object . assign ( { } , this . headers ) ,
response : { } ,
xhr : false ,
iframe : false ,
} ;
file = Object . assign ( defaultFile , file )
if ( ! file . id ) {
file . id = Math . random ( ) . toString ( 36 ) . substr ( 2 ) ;
}
if ( ! this . multiple ) {
this . clear ( ) ;
}
file = this . files [ this . files . push ( file ) - 1 ] ;
this . _files [ file . id ] = file ;
this . _uploadEvents ( 'add' , file ) ;
} ,
_uploadEvents ( name , file ) {
this . $dispatch && this . $dispatch ( name , file , this ) ;
this [ name ] && this [ name ] ( file ) ;
this . events && this . events [ name ] && this . events [ name ] ( file , this ) ;
} ,
_drop ( value ) {
if ( this . dropElement && this . $mode === 'html5' ) {
/ / 移 除 挂 载
if ( this . dropElement && this . mode === 'html5' ) {
try {
window . document . removeEventListener ( 'dragenter' , this . _onDragenter , false ) ;
window . document . removeEventListener ( 'dragleave' , this . _onDragleave , false ) ;
@ -223,18 +277,21 @@ export default {
} else {
this . dropElement = this . drop ;
}
if ( this . dropElement && this . $mode === 'html5' ) {
if ( this . dropElement && this . mode === 'html5' ) {
window . document . addEventListener ( 'dragenter' , this . _onDragenter , false ) ;
window . document . addEventListener ( 'dragleave' , this . _onDragleave , false ) ;
this . dropElement . addEventListener ( 'dragover' , this . _onDragover , false ) ;
this . dropElement . addEventListener ( 'drop' , this . _onDrop , false ) ;
}
} ,
_onDragenter ( e ) {
this . _dropActive ++ ;
this . dropActive = ! ! this . _dropActive ;
e . preventDefault ( ) ;
} ,
_onDragleave ( e ) {
e . preventDefault ( ) ;
this . _dropActive -- ;
@ -246,40 +303,7 @@ export default {
e . preventDefault ( ) ;
} ,
_addFileUpload ( hiddenData , file ) {
var defaultFile = {
size : - 1 ,
name : 'Filename' ,
progress : '0.00' ,
speed : 0 ,
active : false ,
error : '' ,
errno : '' ,
success : false ,
data : { } ,
request : {
headers : { } ,
data : { }
}
} ;
for ( let key in defaultFile ) {
if ( typeof file [ key ] == 'undefined' ) {
file [ key ] = defaultFile [ key ] ;
}
}
if ( ! file . id ) {
file . id = Math . random ( ) . toString ( 36 ) . substr ( 2 ) ;
}
if ( ! this . multiple ) {
this . clear ( ) ;
}
this . _files [ file . id ] = hiddenData ;
file = this . files [ this . files . push ( file ) - 1 ] ;
this . _files [ file . id ] . _file = file ;
this . _uploadEvents ( 'addFileUpload' , file ) ;
} ,
_onDrop ( e ) {
this . _dropActive = 0 ;
this . dropActive = false ;
@ -287,7 +311,7 @@ export default {
if ( e . dataTransfer . files . length ) {
for ( let i = 0 ; i < e . dataTransfer . files . length ; i ++ ) {
let file = e . dataTransfer . files [ i ] ;
this . _ addFileUpload( { file : file } , { size : file . size , name : file . name } ) ;
this . addFileUpload( { file : file , size : file . size , name : file . name } ) ;
if ( ! this . multiple ) {
break ;
}
@ -295,102 +319,106 @@ export default {
}
} ,
_addFileUploads ( el ) {
var Component = this . $options . components . inputFile ;
new Component ( {
parent : this ,
el : el ,
} ) ;
this . uploaded = false ;
_addInputFileElement ( el ) {
if ( el . files ) {
for ( let i = 0 ; i < el . files . length ; i ++ ) {
let file = el . files [ i ] ;
this . _addFileUpload( { file : file , el : el } , { size : file . size , name : file . name } ) ;
this . addFileUpload ( { size : file . size , name : file . name , file : file , el : el } ) ;
}
} else {
this . _ addFileUpload( { el : el } , { size : - 1 , name : el . value . replace ( /^.*?([^\/\\\r\n]+)$/ , '$1' ) } ) ;
this . addFileUpload( { name : el . value . replace ( /^.*?([^\/\\\r\n]+)$/ , '$1' ) , el : el } ) ;
}
var Component = this . $options . components . InputFile ;
var inputFile = new Component ( {
parent : this ,
el : el ,
} ) ;
} ,
_fileUploads ( ) {
if ( ! this . active ) {
return ;
}
for ( ; this . _index < this . files . length ; this . _index ++ ) {
var file = this . files [ this . _index ] ;
if ( file . active || file . success || file . err n o) {
if ( file . active || file . success || file . err or ) {
continue ;
}
if ( this . size && this . size > 0 && file . size >= 0 && file . size > this . size ) {
file . error = 'Size' ;
file . errno = 'size' ;
file . error = 'size' ;
continue ;
}
if ( this . extensions && ( this . extensions . length || typeof this . extensions . length == 'undefined' ) ) {
var extensions = this . extensions ;
if ( typeof extensions == 'object' && extensions instanceof RegExp ) {
} else {
if ( typeof extensions == 'string' ) {
extensions = extensions . split ( ',' ) . map ( function ( value ) {
return value . trim ( ) ;
} ) . filter ( function ( value ) {
return value ;
} ) ;
extensions = extensions . split ( ',' ) . map ( ( value ) => value . trim ( ) ) . filter ( value => value ) ;
}
extensions = new RegExp ( '\\.(' + extensions . join ( '|' ) . replace ( /\./g , '\\.' ) + ')$' , 'i' ) ;
}
if ( file . name . search ( extensions ) == - 1 ) {
file . error = 'Extension' ;
file . errno = 'extension' ;
file . error = 'extension' ;
continue ;
}
}
if ( this . $ mode == 'html5' ) {
if ( this . putAction || file . putAction ) {
if ( this . mode == 'html5' ) {
if ( file . putAction ) {
this . _fileUploadPut ( file ) ;
} else if ( this . postAction || file . postAction ) {
} else if ( file . postAction ) {
this . _fileUploadHtml5 ( file ) ;
} else {
file . error = 'Not Support' ;
file . errno = 'not_support' ;
file . error = 'not_support' ;
continue ;
}
} else {
if ( this . postAction || file . postAction ) {
if ( file . postAction ) {
this . _fileUploadHtml4 ( file ) ;
} else {
file . error = 'Not Support' ;
file . errno = 'not_support' ;
file . error = 'not_support' ;
continue ;
}
}
return ;
}
this . active = false ;
this . uploaded = true ;
} ,
_fileUploadXhr ( xhr , file , data ) {
var _self = this ;
var hiddenData = this . _files [ file . id ] ;
var fileUploads = false ;
var complete = false ;
var speedTime = 0 ;
var speedLoaded = 0 ;
xhr . upload . onprogress = function ( e ) {
/ / 已 移 除
if ( file . removed ) {
xhr . abort ( ) ;
return ;
}
/ / 终 止
if ( ! _self . active || ! file . active ) {
xhr . abort ( ) ;
return ;
}
/ / 进 度
if ( e . lengthComputable ) {
file . progress = ( e . loaded / e . total * 100 ) . toFixed ( 2 ) ;
var speedTime2 = Math . round ( Date . now ( ) / 1000 ) ;
@ -400,39 +428,31 @@ export default {
speedTime = speedTime2 ;
}
}
_self . _uploadEvents ( 'fileUploadProgress' , file ) ;
} ;
_self . _uploadEvents ( 'progress' , file ) ;
}
var callback = function ( e ) {
switch ( e . type ) {
case 'timeout' :
file . errno = 'timeout' ;
file . error = 'Timeout' ;
file . error = 'timeout' ;
break ;
case 'abort' :
file . errno = 'abort' ;
file . error = 'Abort' ;
file . error = 'abort' ;
break ;
case 'error' :
if ( ! xhr . status ) {
file . errno = 'network' ;
file . error = 'Network' ;
file . error = 'network' ;
} else if ( xhr . status >= 500 ) {
file . errno = 'server' ;
file . error = 'Server' ;
file . error = 'server' ;
} else if ( xhr . status >= 400 ) {
file . errno = 'denied' ;
file . error = 'Denied' ;
file . error = 'denied' ;
}
break ;
default :
if ( xhr . status >= 500 ) {
file . errno = 'server' ;
file . error = 'Server' ;
file . error = 'server' ;
} else if ( xhr . status >= 400 ) {
file . errno = 'denied' ;
file . error = 'Denied' ;
file . error = 'denied' ;
} else {
file . progress = '100.00' ;
file . success = true ;
@ -442,15 +462,16 @@ export default {
if ( xhr . responseText ) {
var contentType = xhr . getResponseHeader ( 'Content-Type' ) ;
if ( contentType && contentType . indexOf ( '/json' ) != - 1 ) {
file . data = JSON . parse ( xhr . responseText ) ;
file . response = JSON . parse ( xhr . responseText ) ;
} else {
file . data = xhr . responseText ;
file . response = xhr . responseText ;
}
}
if ( ! fileUploads ) {
fileUploads = true ;
if ( ! complete ) {
complete = true ;
if ( ! file . removed ) {
_self . _uploadEvents ( 'after FileUpload ', file ) ;
_self . _uploadEvents ( 'after ', file ) ;
}
setTimeout ( function ( ) {
_self . _fileUploads ( ) ;
@ -458,138 +479,115 @@ export default {
}
} ;
/ / 事 件
xhr . onload = callback ;
xhr . onerror = callback ;
xhr . onabort = callback ;
xhr . ontimeout = callback ;
if ( this . timeout ) {
xhr . timeout = this . timeout ;
/ / 超 时
if ( file . timeout ) {
xhr . timeout = file . timeout ;
}
xhr . onload = callback ;
xhr . onerror = callback ;
xhr . onabort = callback ;
xhr . ontimeout = callback ;
if ( this . timeout ) {
xhr . timeout = this . timeout ;
}
/ / h e a d e r s
xhr . setRequestHeader ( 'X-Requested-With' , 'XMLHttpRequest' ) ;
for ( var key in this . request . headers ) {
xhr . setRequestHeader ( key , this . request . headers [ key ] ) ;
}
for ( var key in file . request . headers ) {
xhr . setRequestHeader ( key , file . request . headers [ key ] ) ;
for ( let key in file . headers ) {
xhr . setRequestHeader ( key , file . headers [ key ] ) ;
}
/ / 开 始 上 传
xhr . send ( data ) ;
file . active = true ;
hiddenData . xhr = xhr ;
file . xhr = xhr
/ / 定 时 执 行 检 测
var interval = setInterval ( function ( ) {
if ( ! _self . active || ! file . active || file . success || file . errno ) {
if ( ! _self . active || ! file . active || file . success || file . err or ) {
clearInterval ( interval ) ;
if ( ! file . success && ! file . err n o) {
if ( ! file . success && ! file . err or ) {
xhr . abort ( ) ;
}
}
} , 100 ) ;
this . _uploadEvents ( 'beforeFileUpload' , file ) ;
/ / 开 始 上 传
this . _uploadEvents ( 'before' , file ) ;
} ,
_fileUploadPut ( file ) {
var _self = this ;
var querys = { } ;
for ( let key in this . request . data ) {
querys [ key ] = this . request . data [ key ] ;
}
for ( let key in file . request . data ) {
querys [ key ] = file . request . data [ key ] ;
}
_fileUploadPut ( file ) {
var querys = Object . assign ( { } , file . data )
var queryArray = [ ] ;
for ( let key in querys ) {
if ( querys [ key ] !== null && typeof querys [ key ] !== 'undefined' ) {
queryArray . push ( encodeURIComponent ( key ) + '=' + encodeURIComponent ( querys [ key ] ) ) ;
}
}
var queryString = queryArray . length ? '?' + queryArray . join ( '&' ) : '' ;
var queryString = queryArray . length ? ( file . putAction . indexOf ( '?' ) == - 1 ? '?' : '&' ) + queryArray . join ( '&' ) : '' ;
var xhr = new XMLHttpRequest ( ) ;
xhr . open ( 'PUT' , ( file . putAction || this . putAction ) + queryString ) ;
this . _fileUploadXhr ( xhr , file , this . _files [ file . id ] . file ) ;
xhr . open ( 'PUT' , file . putAction + queryString ) ;
this . _fileUploadXhr ( xhr , file , file . file ) ;
} ,
_fileUploadHtml5 ( file ) {
var form = new window . FormData ( ) ;
form . append ( this . name , this . _files [ file . id ] . file ) ;
for ( var key in this . request . data ) {
form . append ( key , this . request . data [ key ] ) ;
form . append ( this . name , file . file ) ;
for ( var key in file . data ) {
form . append ( key , file . data [ key ] ) ;
}
for ( var key in file . request . data ) {
form . append ( key , file . request . data [ key ] ) ;
}
var xhr = new XMLHttpRequest ( ) ;
xhr . open ( 'POST' , file . postAction || this . postAction ) ;
xhr . open ( 'POST' , file . postAction ) ;
this . _fileUploadXhr ( xhr , file , form ) ;
} ,
_fileUploadHtml4 ( file ) {
var _self = this ;
var hiddenData = this . _files [ file . id ] ;
var fileUploads = false ;
var complete = false ;
var keydown = function ( e ) {
if ( e . keyCode == 27 ) {
e . preventDefault ( ) ;
}
} ;
}
var iframe = document . createElement ( 'iframe' ) ;
iframe . id = 'upload-iframe-' + file . id ;
iframe . name = 'upload-iframe-' + file . id ;
iframe . src = 'about:blank' ;
iframe . style . width = '1px' ;
iframe . style . height = '1px' ;
iframe . style . top = '-9999px' ;
iframe . style . left = '-9999px' ;
iframe . style . position = 'absolute' ;
iframe . style . marginTop = '-9999em' ;
iframe . style = {
width : '1px' ,
height : '1px' ,
top : '-9999px' ,
left : '-9999px' ,
position : 'absolute' ,
marginTop : '-9999em' ,
}
var form = document . createElement ( 'form' ) ;
form . action = file . postAction || this . postAction ;
form . action = file . postAction ;
form . name = 'upload-form-' + file . id ;
form . setAttribute ( 'method' , 'POST' ) ;
form . setAttribute ( 'target' , 'upload-iframe-' + file . id ) ;
form . setAttribute ( 'enctype' , 'multipart/form-data' ) ;
form . appendChild ( hiddenData . el ) ;
for ( var key in this . request . data ) {
var input = document . createElement ( 'input' ) ;
input . type = 'hidden' ;
input . name = key ;
input . value = this . request . data [ key ] ;
form . appendChild ( input ) ;
}
form . appendChild ( file . el ) ;
for ( var key in file . request . data ) {
var input = document . createElement ( 'input' ) ;
for ( let key in file . data ) {
let input = document . createElement ( 'input' ) ;
input . type = 'hidden' ;
input . name = key ;
input . value = file .request . data [key ] ;
input . value = file [ key ] ;
form . appendChild ( input ) ;
}
var getDocumentData = function ( ) {
var doc ;
try {
@ -613,31 +611,26 @@ export default {
var callback = function ( e ) {
switch ( e . type ) {
case 'abort' :
file . errno = 'abort' ;
file . error = 'Abort' ;
file . error = 'abort' ;
break ;
case 'error' :
var data = getDocumentData ( ) ;
if ( file . errno ) {
if ( file . error ) {
} else if ( data === null ) {
file . errno = 'network' ;
file . error = 'Network' ;
file . error = 'network' ;
} else {
file . errno = 'denied' ;
file . error = 'Denied' ;
file . error = 'denied' ;
}
break ;
default :
var data = getDocumentData ( ) ;
if ( file . errno ) {
if ( file . error ) {
} else if ( data === null ) {
file . errno = 'network' ;
file . error = 'Network' ;
file . error = 'network' ;
} else {
file . progress = '100.00' ;
file . success = true ;
@ -654,13 +647,13 @@ export default {
}
file . data = data ;
}
if ( ! fileUploads ) {
if ( ! complete ) {
complete = true ;
document . body . removeEventListener ( 'keydown' , keydown ) ;
document . body . removeEventListener ( 'keydown' , keydown ) ;
fileUploads = true ;
iframe . parentNode && iframe . parentNode . removeChild ( iframe ) ;
if ( ! file . removed ) {
_self . _uploadEvents ( 'after FileUpload ', file ) ;
_self . _uploadEvents ( 'after ', file ) ;
}
setTimeout ( function ( ) {
_self . _fileUploads ( ) ;
@ -669,6 +662,7 @@ export default {
} ;
setTimeout ( function ( ) {
document . body . appendChild ( iframe ) . appendChild ( form ) . submit ( ) ;
iframe . onload = callback ;
@ -676,21 +670,21 @@ export default {
iframe . onabort = callback ;
file . active = true ;
hiddenData . iframe = iframe ;
file . iframe = iframe ;
document . body . addEventListener ( 'keydown' , keydown ) ;
var interval = setInterval ( function ( ) {
if ( ! _self . active || ! file . active || file . success || file . err n o) {
if ( ! _self . active || ! file . active || file . success || file . err or ) {
clearInterval ( interval ) ;
if ( ! file . success && ! file . err n o) {
if ( ! file . success && ! file . err or ) {
iframe . onabort ( { type : 'abort' } ) ;
}
}
} , 50 ) ;
_self . _uploadEvents ( 'before FileUpload ', file ) ;
_self . _uploadEvents ( 'before ', file ) ;
} , 10 ) ;
} ,
}
}
< / script >